Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Linux Admins By James Joyner IV · · 10 min read

Migrating Linux Users and Groups Between Servers with AI

Moving accounts to a new box means matching UIDs, hashes, and group memberships without breaking file ownership. Here's a safe migration workflow with AI help.

  • #linux
  • #users
  • #migration
  • #permissions
  • #passwd

Server migrations are mostly fine until you hit the user accounts. You spin up the new box, copy the data, and discover that every file is owned by UID 1004 which on the new server maps to a completely different person — or nobody at all. Migrating Linux users and groups means preserving not just usernames but the exact UIDs, GIDs, password hashes, group memberships, and home directories, and the relationships between /etc/passwd, /etc/shadow, and /etc/group are subtle enough that mistakes are easy and silent. I’ve come to lean on an AI assistant here as a fast junior engineer that understands those file relationships and helps me build a careful migration plan, while I review and execute every step on the actual hosts. Here’s the workflow.

Understanding what actually needs to move

Four files hold the account state, and they must stay consistent with each other.

getent passwd | awk -F: '$3 >= 1000 {print}'
getent group | awk -F: '$3 >= 1000 {print}'

Filtering on UID/GID ≥ 1000 isolates real human accounts from system accounts, which you generally do not migrate — system UIDs are assigned by packages on the new box. Paste this list into an AI and ask it to confirm which entries are human accounts worth migrating versus service accounts to leave alone. It’s a good sanity check before you copy anything.

Exporting the accounts safely

You export the relevant lines from each file, but /etc/shadow contains password hashes and is extremely sensitive.

sudo getent passwd | awk -F: '$3 >= 1000 && $3 < 60000' > /tmp/passwd.export
sudo getent group  | awk -F: '$3 >= 1000 && $3 < 60000' > /tmp/group.export
sudo awk -F: 'NR==FNR{u[$1];next} $1 in u' /tmp/passwd.export /etc/shadow > /tmp/shadow.export

That last line pulls only the shadow entries for the users you’re migrating. This is the absolute hard line on AI: you can ask the model to help you construct the awk, but the contents of /etc/shadow — the password hashes — never get pasted into a chat tool. Hashes are credentials. If a hash touches an LLM clipboard, you force a password reset for that user. I keep the migration prompt templates (which reference the files but never their contents) in a shared prompt library.

Pro Tip: Migrate UIDs and GIDs exactly, never let the new server auto-assign them. If UID 1004 means a different user on each box, every file chowned by number is now owned by the wrong person — a silent, dangerous permission drift that’s miserable to untangle later.

Importing on the new server

On the target, you recreate the groups first (so GIDs exist before users reference them), then users with explicit UIDs.

# groups first, with explicit GID
sudo groupadd -g 1005 ops
# then users with explicit UID and primary group
sudo useradd -u 1004 -g 1005 -m -s /bin/bash jdoe

Order matters: a user’s primary group must exist first. Ask the AI to read your exports and generate the groupadd/useradd sequence in the correct dependency order, with the right -u/-g flags. It handles the ordering reliably where a hand-written script often gets it backwards. Review every generated line before running it — confirm the UIDs match the source exactly.

Restoring password hashes

Rather than reset everyone’s password, you restore the hashes so logins keep working.

sudo cp /etc/shadow /etc/shadow.bak
# apply the exported shadow lines with chpasswd -e, after manual review

chpasswd -e accepts pre-hashed entries. You do this manually and carefully, with a backup, because a botched /etc/shadow can lock everyone out including root. The AI can explain the format of a shadow line (the hash, the last-change day, the aging fields) so you understand what you’re restoring — but it does not see the hashes and does not run the command.

Fixing file ownership

If you copied data preserving numeric ownership, and you matched UIDs exactly, ownership should already be correct. Verify it.

find /home/jdoe ! -user jdoe -ls | head
sudo chown -R jdoe:ops /home/jdoe   # only if a mismatch is found

find ! -user surfaces any file owned by the wrong account. Paste a sample of mismatches to the AI and it’ll help you reason about whether it’s a UID drift or an expected service-owned file you should leave alone.

Validating logins before cutover

Don’t declare victory until a real login works end to end.

sudo -u jdoe -i whoami
getent passwd jdoe && groups jdoe

A clean login with the right group memberships means the migration held. The AI helped plan it; this proves it on the real host. If anything’s off, the journal (journalctl -u sshd) tells you why, and the model is fluent in PAM and auth errors.

Handling UID collisions on the target

The migration gets interesting when the new server already has accounts in the same UID range — a package installed a service user at UID 1004, and now your human user wants the same number. You have to detect and resolve these before importing.

# find UIDs on the target that overlap your import set
comm -12 <(awk -F: '{print $3}' /tmp/passwd.export | sort) \
         <(getent passwd | awk -F: '{print $3}' | sort)

That comm surfaces every colliding UID. Paste both the collision list and your export to the AI and ask it to propose a remapping plan — which accounts to renumber and what find ... -exec chown commands will fix the on-disk files for the renumbered ones. It reasons through the ripple effects (every file owned by the old number needs updating) more reliably than I do under time pressure. You review the plan line by line, because a wrong chown -R across the wrong tree is its own incident.

Pro Tip: Resolve UID collisions before you copy any data, not after. If you renumber a user once files already exist on the new box, you’re chasing down every file they own with find -uid; do it first and the data copy lands on already-correct ownership.

Migrating SSH keys and login state

Accounts aren’t just passwd entries — users expect their SSH keys and shell history to come along, and those live in the home directory.

rsync -aHX --numeric-ids /home/jdoe/ newhost:/home/jdoe/

The --numeric-ids flag is the critical one: it preserves ownership by number rather than remapping by name, which is exactly what you want once UIDs match. -H preserves hardlinks and -X extended attributes. Ask the AI to explain each rsync flag here so you understand why --numeric-ids is non-negotiable for a migration — getting it wrong silently re-owns every file to whatever name happens to map on the target.

Keeping it safe

This migration touches credentials, so the safety discipline is at its strictest. Password hashes never enter a chat — they’re credentials, full stop. The AI helps build the export awk, the import sequence, and explains file formats, but it never sees /etc/shadow contents and never runs useradd, chpasswd, or chown against your servers. It is a fast junior engineer that knows how the account files relate; the human handles every step that touches hashes or production. A bad /etc/shadow can lock out root, so back it up and verify on a test login before cutover. For change tracking, our code-review dashboard keeps the migration plan and its review together.

Conclusion

User and group migration is where server moves quietly go wrong, and the fix is discipline: match UIDs and GIDs exactly, preserve hashes without ever exposing them, and verify a real login before cutover. An AI copilot makes the planning faster — it understands the passwd/shadow/group relationships and builds the correct import order — while the human owns every credential-touching step. More in the Linux admin category, and the Linux admin prompt pack includes the migration-planning prompts that keep these moves clean.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.