Creating and Managing Users (useradd, usermod)

Every process on a Linux system runs as some user, and every file belongs to one. Before a person or a service can log in, own files, or run scheduled jobs safely, an administrator has to create an account for them — and later adjust its group memberships, shell, or lock it when it is no longer needed. The two workhorse commands for this are useradd, which creates new accounts, and usermod, which modifies existing ones. Together they are how you manage every human and service identity on a Linux box from the command line.

Overview: How Linux Manages Users

Linux does not really know names like alice or bob. Internally, the kernel only cares about numeric IDs: a UID (user ID) for ownership checks on files and processes, and one or more GIDs (group IDs) for group-based permission checks. The mapping from human-readable names to those numbers lives in a handful of plain text files that useradd and usermod edit for you:

  • /etc/passwd — one line per user: name, UID, primary GID, comment, home directory, and login shell.
  • /etc/shadow — the actual password hashes and password-aging rules, readable only by root.
  • /etc/group — one line per group: name, GID, and the list of members who have it as a supplementary group.
  • /etc/gshadow — group passwords and administrators (rarely used today).

Because the password hash lives in /etc/shadow rather than /etc/passwd, the password field in /etc/passwd is always just x — a placeholder telling the system “look in shadow.” This split exists because /etc/passwd must be world-readable (many programs need to resolve UIDs to names), while password hashes must not be.

The /etc/passwd fields

Field Meaning
Username Login name, e.g. alice
Password Always x — the real hash lives in /etc/shadow
UID Numeric user ID the kernel actually uses for ownership checks
GID Numeric ID of the user’s primary group
GECOS Comment field, usually the full name (the name comes from an old General Electric operating system that used this field for job routing)
Home directory Path set as $HOME on login, e.g. /home/alice
Shell Program started on login, e.g. /bin/bash or /usr/sbin/nologin for accounts that should never get an interactive shell

UIDs are not handed out randomly. /etc/login.defs defines a range (UID_MIN/UID_MAX, typically starting at 1000 on modern Debian, Ubuntu, and RHEL/Fedora systems) for regular human accounts. UIDs below that — 0 for root, then a block for daemons like www-data or sshd — are system accounts, created automatically by packages or manually with useradd -r. useradd and usermod both ship in the same package on every mainstream distro (passwd on Debian/Ubuntu, shadow-utils on RHEL/Fedora) and are installed by default, so there is normally nothing to apt install or dnf install before you can use them.

A quick note on tooling: Debian and Ubuntu also ship adduser, a friendlier Perl wrapper around useradd that prompts you interactively, creates the home directory, and sets a password by default. useradd itself is the lower-level, distro-portable tool with almost nothing enabled unless you pass flags for it — which makes it the right choice for scripts, but a trap for anyone expecting adduser-like defaults.

Syntax

Both commands take the target username last, after any options:

useradd [options] <username>
usermod [options] <username>

Common useradd options

Option Meaning
-m Create the home directory, populated from /etc/skel
-d <dir> Use a specific path as the home directory instead of the default /home/<username>
-s <shell> Set the login shell, e.g. /bin/bash
-c <comment> Set the GECOS comment field, usually the full name
-u <uid> Request a specific numeric UID instead of the next free one
-g <group> Set the primary group by name or GID
-G <groups> Comma-separated list of supplementary groups to join
-e <YYYY-MM-DD> Set an account expiration date
-r Create a system account (low UID, usually no home directory, no password-aging)

Common usermod options

Option Meaning
-aG <groups> Append to the supplementary group list — always pair -a with -G
-G <groups> Replace the entire supplementary group list (dangerous without -a)
-s <shell> Change the login shell
-d <dir> -m Move the home directory to a new path and relocate its contents
-c <comment> Change the GECOS comment field
-l <name> Rename the login (does not rename or move the home directory)
-L Lock the account by prefixing the password hash in /etc/shadow with !
-U Unlock a previously locked account
-e <YYYY-MM-DD> Change the account expiration date

Examples

Example 1: Create a basic user with a home directory

sudo useradd -m -s /bin/bash alice
sudo passwd alice

Output of the passwd prompt:

New password: 
Retype new password: 
passwd: password updated successfully

-m creates /home/alice and copies the skeleton files from /etc/skel (things like .bashrc and .profile) into it, then makes alice the owner. -s /bin/bash sets the login shell. Notice that useradd by itself does not set a password — the new account is locked (its shadow entry starts with !) until you run passwd. Without that second step, alice could not log in with a password at all, though key-based SSH login would still work once a key is authorized.

Verify the account:

id alice
uid=1001(alice) gid=1001(alice) groups=1001(alice)

Example 2: Create a user with a specific UID, comment, and groups

sudo useradd -m -u 1500 -c "Bob Johnson, DevOps" -G sudo,docker -s /bin/bash bob

This pins Bob’s UID to 1500 (useful when the same UID must match across several servers sharing NFS storage), records his full name and role in the GECOS field, and immediately adds him to the sudo and docker supplementary groups at creation time — no separate usermod step needed for a brand-new account.

getent passwd bob
bob:x:1500:1500:Bob Johnson, DevOps:/home/bob:/bin/bash
groups bob
bob : bob sudo docker

Example 3: Modify an existing account with usermod

sudo usermod -aG docker alice
sudo usermod -s /bin/bash alice
sudo usermod -L bob

The first line adds alice to the docker group without touching any group she already belongs to, because -a (append) is combined with -G. The second changes her shell. The third locks Bob’s account by inserting ! in front of his password hash in /etc/shadow — he can no longer authenticate with a password, but the account, its files, and its UID still exist, so nothing referencing bob breaks.

groups alice
alice : alice docker

How It Works Step by Step

When you run sudo useradd -m -s /bin/bash alice, roughly this happens:

  1. sudo re-executes useradd as root (via PAM authentication), since only root can write to /etc/passwd and /etc/shadow.
  2. useradd reads defaults from /etc/login.defs and /etc/default/useradd — things like the UID range and whether a private group per user should be created.
  3. It picks the next free UID at or above UID_MIN (unless you supplied -u).
  4. On Debian/Ubuntu, by default it also creates a new group with the same name and a matching GID, so each user gets their own private primary group rather than sharing a generic users group.
  5. A new line is appended to /etc/passwd with the username, UID, GID, GECOS, home path, and shell.
  6. A matching line is appended to /etc/shadow with the password field set to ! (locked, no password yet) and password-aging fields taken from /etc/login.defs.
  7. Because -m was given, /home/alice is created, the contents of /etc/skel are copied in, and the whole tree is chown‘d to alice:alice and set to mode 700.

When you later run sudo usermod -aG docker alice, usermod reads /etc/group, finds the docker line, and appends alice to its member list, then writes the file back. It does not touch /etc/passwd, her primary GID, or her password at all — only the one group line changes.

Common Mistakes

Mistake 1: Using -G instead of -aG

Wrong — this looks like it adds a group, but it actually replaces the entire supplementary group list with just docker, silently removing every other group membership alice had:

sudo usermod -G docker alice

Correct — always pair -a (append) with -G when your intent is to add one group:

sudo usermod -aG docker alice

Mistake 2: Forgetting -m and getting a user with no home directory

Wrong — without -m, useradd still creates the account, but no home directory is ever made:

sudo useradd -s /bin/bash carol
ls: cannot access '/home/carol': No such file or directory

Correct — pass -m whenever the account needs a real home directory (skip it only for intentional system/service accounts):

sudo useradd -m -s /bin/bash carol

Mistake 3: Deleting a user without -r and leaving orphaned files

Wrong — plain userdel removes the account from /etc/passwd and /etc/shadow but leaves the home directory and mail spool sitting on disk, owned by a UID that no longer maps to any name:

sudo userdel carol

Correct — once you have confirmed the data is no longer needed, use -r to remove the home directory and mail spool along with the account:

sudo userdel -r carol

Mistake 4: Editing /etc/passwd or /etc/shadow by hand

Opening these files directly in a text editor risks a corrupted file — a stray line break or a process reading the file mid-edit can lock every account out of the system. Always go through useradd/usermod, or use vipw (and vipw -s for the shadow file) if manual editing is unavoidable; it locks the file and validates it on save.

Best Practices

  • Always pair -a with -G in usermod — bare -G silently wipes existing group memberships.
  • Pass -m for any account that needs to log in interactively; skip it only for deliberate system/service accounts created with -r.
  • Give real accounts a meaningful -c comment so getent passwd output is identifiable months later.
  • Use -e to set an expiration date on temporary or contractor accounts instead of relying on someone to remember to remove them.
  • Lock accounts first with usermod -L (or passwd -l) instead of deleting immediately — you can restore access instantly if it turns out to be needed, whereas userdel -r is not reversible.
  • Verify every change with id <username>, groups <username>, or getent passwd <username> — do not assume the command did what you intended.
  • Use adduser for interactive, manual administration on Debian/Ubuntu; use useradd in scripts, since it behaves consistently across distros and never prompts.
  • Assign explicit UIDs/GIDs with -u/-g when the same account must resolve to the same numeric ID across multiple servers sharing NFS-mounted storage.
  • Never edit /etc/passwd or /etc/shadow directly — use the dedicated commands, or vipw if you truly must edit by hand.

Practice Exercises

  1. Create a user named devops with a home directory, Bash as the login shell, and immediate membership in the sudo group — do it in a single useradd command, then set a password for the account.
  2. An existing user maria is already a member of the developers group. Add her to the docker group as well without losing her existing membership, then confirm with a command that lists all of a user’s groups.
  3. Lock the account of a former contractor named guest01 without deleting it, verify that the account is locked by inspecting the relevant field, then decide what you would check before eventually running userdel -r on it.

Summary

  • useradd creates accounts by writing entries to /etc/passwd and /etc/shadow and, with -m, building a home directory from /etc/skel.
  • A new account has no usable password until you run passwd — it starts locked.
  • usermod changes an existing account’s shell, comment, groups, UID mapping in place, or lock state — it never creates a new user.
  • Always use -aG, never bare -G, when adding someone to a group with usermod.
  • The GID and supplementary groups in /etc/group control group-based file permissions; the UID in /etc/passwd is what the kernel actually checks.
  • Prefer locking (usermod -L) over deleting when an account might need to come back, and always use userdel -r deliberately, not by default.