Create a Linux User Safely with useradd

A new starter needs a login, and useradd will happily create one with no home, the wrong shell and no password. Here is how to get it right first time. You will create a regular account with a home directory, a chosen shell and supplementary groups, then verify what changed. It also covers service accounts and how to remove an account once you have checked it owns nothing you need. Allow about fifteen minutes.

Privilege boundary: Reading defaults is ordinary. Creating or deleting an account changes system identity files and needs elevated privileges.

1. Inspect the defaults

Start with the read-only form. It prints the values from /etc/default/useradd that fill in any option you leave out:

$ useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/sh
SKEL=/etc/skel
CREATE_MAIL_SPOOL=no
LOG_INIT=yes

Confirm the installed binary and version before you copy examples into automation:

$ command -v useradd
/usr/sbin/useradd
$ dpkg-query -W -f='${Package} ${Version}\n' passwd
passwd 1:4.13+dfsg1-4ubuntu3.2
$ useradd --help | sed -n '1,2p'
Usage: useradd [options] LOGIN

Checkpoint: If your output differs, your local defaults win over this guide.

Tip: On Debian the manpage points administrators at adduser as the usual higher-level tool. useradd is the lower-level utility, used here because you want its options and predictable mechanics.

2. Choose a valid, unused login name

Use a short name such as ada, not a display name or an email address. This implementation rejects:

$ getent passwd ada
$ getent group ada

Checkpoint: No output means neither name exists in the databases getent consults. Any result is a stop sign: pick another login or investigate the identity service before changing anything.

A name can exist in NIS or LDAP even when a local file search misses it. Let useradd run its normal checks rather than forcing a duplicate with -o; duplicate UIDs make file ownership and access decisions much harder to reason about.

3. Create a regular account with a home

Pick the shell and groups deliberately:

$ sudo useradd -m -s /bin/bash -G audio,video ada

With the local defaults above, this also creates a same-named primary group. It does not set a usable password: without -p, the new account is locked with no password defined.

Warning: Do not use -p with a plaintext password. The option expects a crypt-formatted value, and even that value is visible to anyone who can inspect the process list.

Set the password with the normal tool instead, ideally from a controlled terminal:

$ sudo passwd ada
New password:
Retype new password:
passwd: password updated successfully

Tip: For an SSH account, check your organisation's authentication policy before enabling it. Setting a local password does not by itself grant SSH access.

4. Verify the account before handing it over

Check the account record, group membership, home directory and shell. All read-only:

$ getent passwd ada
ada:x:1001:1001::/home/ada:/bin/bash
$ id ada
uid=1001(ada) gid=1001(ada) groups=1001(ada),29(audio),44(video)
$ sudo test -d /home/ada && echo 'home directory exists'
home directory exists
$ sudo passwd -S ada
ada P ...

Checkpoint: The passwd record names the expected home and shell, id shows the intended groups, and the directory exists. Your UID, GID, group numbers and password-status fields will differ, so check the names rather than copying these numbers.

Then test the login shell without starting a session or changing account state:

$ sudo -u ada /bin/bash -c 'printf "uid=%s home=%s shell=%s\n" "$(id -u)" "$HOME" "$SHELL"'
uid=1001 home=/home/ada shell=/bin/bash

sudo -u changes the effective user for this one command. It does not prove every interactive login path works, but it catches a misspelled shell or an unusable home directory early.

5. Create a service account for daemons

When nobody should log in, use a system account. It gets an ID from the system-user range, no home directory by default, and no password-ageing information:

$ sudo useradd --system --no-create-home --shell /usr/sbin/nologin exampled
$ getent passwd exampled
exampled:x:998:998::/nonexistent:/usr/sbin/nologin

6. Change defaults only on purpose

useradd -D on its own only displays defaults. Add options and it writes /etc/default/useradd, which is a privileged, persistent change:

$ sudo useradd -D -s /bin/bash
$ useradd -D | grep '^SHELL='
SHELL=/bin/bash

This affects later accounts, not existing ones. Record the previous output before changing a production host so you can put it back.

Recovery: To restore the value seen earlier on this machine, set it back and check it:

$ sudo useradd -D -s /bin/sh
$ useradd -D | grep '^SHELL='
SHELL=/bin/sh

Warning: Do not use -K casually to override UID ranges or password ageing for one account. Those overrides can bypass the host's identity policy, so review them like any other security-sensitive configuration.

7. Remove an account only after checking ownership

Destructive action: Account deletion cannot be undone. Stop services that use the account, inspect its processes and find the files it owns first.

These checks do not delete anything:

$ ps -u exampled -f
$ sudo find / -xdev -user exampled -print 2>/dev/null

Move or reassign files according to your retention policy. Only then remove the account:

$ sudo userdel exampled
$ getent passwd exampled

Checkpoint: No output from the final command means the account is gone from the available databases.

Warning: For a regular account, sudo userdel -r ada also removes the home directory and mail spool where supported. That is irreversible, so back up or archive first and never use -r while you still need the user's files.

Done means