useradd Command in Linux: Create a User That Can Log In

LinuxForDevices featured banner for the useradd command guide, showing the account template feeding a five field account row with two empty slots and one locked password field

useradd prints nothing and exits 0. That silence is not success, because the account it leaves behind has no home directory, a /bin/sh login shell, and a password field locked in /etc/shadow.

I ran each flag on a fresh Ubuntu 24.04 account and read the state back after every one. The flags that carry the account are -m for the home directory, -s for the login shell and -G for the extra group, and the read-back commands below show whether the job finished.

What useradd writes and what it leaves out

An account lives in the passwd and shadow files, and useradd writes those rows from a template it reads at run time rather than from values compiled into the binary. The Linux user administration guide maps the files and the groups around them.

The template is split across the system configuration files. /etc/default/useradd holds the shell, the skeleton directory and the mail spool flag, while /etc/login.defs holds the UID range, the home directory mode and whether each new account gets a group of its own.

Run useradd with -D and no other argument and it prints the first of those files back to you.

useradd -D

SHELL is /bin/sh there rather than /bin/bash. A login shell without readline gives the new user no arrow keys and no tab completion, which reads as a broken account rather than a default.

KeyValue on UbuntuWhat it decides
GROUP100the fallback primary group when no per-user group is made
HOME/homethe base directory, with the account name appended
INACTIVE-1no inactivity lock after the password ages out
EXPIREemptythe account never expires on its own
SHELL/bin/shthe login shell when -s is left out
SKEL/etc/skelthe files copied into a new home directory
CREATE_MAIL_SPOOLnowhether /var/mail/<name> is created
LOG_INITyesreset the lastlog and faillog entries

CREATE_HOME is absent from that list because it lives in /etc/login.defs instead, and Ubuntu ships that file with the variable commented out, which means the default is off.

I checked that row after a bare useradd and the shell field holds /bin/sh while the home directory it names is absent. So the bare command writes the account row and stops.

useradd -D printing the account template beside a bare useradd that leaves the /bin/sh shell and no home directory
useradd -D prints the template. The bare command underneath wrote the account row with /bin/sh, and the home directory it names does not exist

Debian and Ubuntu add a second command on top. adduser is a Perl wrapper that calls useradd with the flags you just saw missing, and it prompts for the password and the full name.

The Debian manual page for useradd calls it a low level utility and says administrators should usually use adduser instead. That advice holds on Debian and Ubuntu, though it is the wrong reading on Fedora.

Pointuseraddadduser
Ships inshadow-utilsthe adduser package
Interfaceflags onlyprompts, with flags for scripts
Creates the home directoryonly with -mby default
Sets the login shellfrom /etc/default/useradd unless -s is passedasks
Sets the passwordnever, unless -p is passedasks
On Fedora and RHELthe command itselfa symbolic link to useradd

The Fedora side points the other way. adduser there is a symbolic link to useradd, so the interactive prompt never appears.

A script that has to run on both uses useradd with explicit flags, because that name means the same thing on every distribution.

Before you run it

The command needs root, which the sudo command grants, plus a name that clears two sets of rules and any group you name with -G already present.

  • sudo or a root shell, because every write lands in /etc
  • a username inside the rules shadow-utils enforces
  • every group in the -G list already created
  • a decision on the home directory and the login shell

A name may hold letters, digits, underscores and dashes, and it may end with a dollar sign. It cannot start with a dash, it cannot be fully numeric, and the ceiling is 256 characters.

A leading dot is legal and worth avoiding, because the home directory inherits the same name and then disappears from a plain ls.

A name that breaks those rules stops the command with exit 19 before anything is written.

The group is the one that catches people out. useradd will not create a group for -G, so a missing name stops the command with exit 6 and leaves no account behind.

sudo groupadd webteam

Groups first, then the account. The groupadd command guide covers the group id and password options if the plain form is not enough.

Create the account

In practice, a single command covers the creation once you name what a usable account needs.

The command that produces a usable account

The group goes first when it is new, then the account.

sudo groupadd webteam
sudo useradd -m -s /bin/bash -G webteam linus

Nothing prints. Reading the account back is what tells you it is finished rather than started.

useradd creating a Linux account, with id and getent passwd showing the uid, gid, groups, home path and shell
The account row reports the uid, the primary group, the supplementary group, the home path and the shell in one line each

I read the passwd row back and its fields run left to right. The account name, an x standing in for the password, the numeric UID, the numeric GID of the primary group, and the home directory followed by the login shell.

That x is a pointer rather than a value. The password itself, or the marker that says there is none, lives in /etc/shadow.

FlagWhat it doesWhat you get without it
-mcreates the home directory from the skeletonno home directory at all
-ssets the login shell in the passwd rowSHELL from /etc/default/useradd, which is /bin/sh
-Gadds supplementary groups, comma separatedonly the primary group
-dsets the home pathHOME plus the account name
-cwrites the fifth field, the descriptionempty
-usets the numeric UIDthe lowest free value above UID_MIN

Where the home directory comes from

-m does two jobs, and the second one is what makes the account feel finished.

It creates the directory and it copies the skeleton into it. On Ubuntu the skeleton is /etc/skel, and the startup files it holds are the ones a new login reads.

The mode comes from HOME_MODE in /etc/login.defs, which Ubuntu sets to 0750. Without that line the umask would decide instead.

ls -ahl on a new Linux home directory showing the three etc skel files and the 0750 directory mode
The skeleton files arrived with -m, and the directory mode is 0750 because that is what HOME_MODE sets

I read the directory back with stat after -m and the mode is 0750, so only the account and its group can enter it. That group is the per-user group useradd created for the account.

-M overrides everything, including a CREATE_HOME turned on in /etc/login.defs. Use it for an account that should exist in the passwd file without a login directory.

sudo useradd -m -d /opt/appsvc -s /usr/sbin/nologin appsvc
sudo useradd -m -k /etc/skel-web myservice
sudo useradd -M -s /bin/bash ephemeral

-d moves the home path and does not create the directory on its own, so it travels with -m. -k points the copy at a different skeleton, and it means nothing unless -m is present.

The shell, the UID, the full name and the expiry

The remaining flags answer the questions that arrive once the account exists.

sudo useradd -m -s /bin/bash -c "Linus Torvalds" -u 1600 linus
sudo useradd -m -e 2027-12-31 trial
sudo useradd -r -s /usr/sbin/nologin metrics
FlagField it fillsWhat to know
-sthe shell field of /etc/passwd/usr/sbin/nologin blocks an interactive login and leaves the account usable for a service
-cthe fifth field, a descriptiondisplay only, no effect on permissions
-uthe numeric UIDmust be free unless -o is passed
-ethe account expiry datewritten as YYYY-MM-DD and read as UTC
-fdays of grace after the password expires0 disables the account the moment the password ages out
-ra system accounttakes a UID from the SYS range and skips the home directory

The UID is the number the kernel uses to decide who owns a file. Leave -u out and useradd hands over the lowest free value above UID_MIN, which Ubuntu sets to 1000.

Expiry arrives in two forms that get mixed up. -e stops the account on a date, while -f decides how long the account survives after the password ages out, which is a different clock.

I created one account with an expiry date and checked it afterwards with chage -l, which reported the account expiry on its own line and left the password lines alone.

The primary group and the -G groups

Every account has exactly one primary group and any number of supplementary groups, and the two flags that set them are one letter apart.

FlagEffectWhere it lands
-gsets the primary group, by name or by numberthe GID field of /etc/passwd
-Gadds supplementary groupsthe membership list in /etc/group

Pass neither and USERGROUPS_ENAB in /etc/login.defs decides. Ubuntu sets it to yes, so useradd creates a group with the same name as the account and makes it the primary.

That group is the second entry in the id output, and it is also the group that owns the home directory.

The -G list is comma separated with no spaces after the commas, and every name in it has to be present before the command runs.

sudo useradd -m -s /bin/bash -G webteam,docker,developers linus

Adding a group after the fact is a different command. The guide to adding a user to a group in Linux covers usermod, and finding the user group of a user covers reading the membership back.

Set the password, then read the account state

useradd leaves the password field locked unless you hand it an encrypted value, and that state is deliberate rather than a defect.

The manual page spells it out. Without -p the new account is locked, with a single exclamation mark in the password field of /etc/shadow.

That marker is not a password and cannot be typed in as one. Every authentication attempt fails against it, so it is a state to check rather than a fault to chase.

sudo getent shadow linus
passwd -S reporting the locked state L before the password is set and the usable state P afterwards
L is the locked state a bare useradd leaves behind, and P is the same account once passwd has set a password

The second field of the passwd -S line carries the status letter, and that letter is the one to read.

LetterMeaningWhat to do
Llocked, with no usable passwordrun passwd to set one
Pa usable password is setnothing
NPno password at allset one, because some channels accept a blank password

I read the shadow entry before setting a password and the field holds that single exclamation mark. Setting the password is its own command, and it asks twice so a typo cannot lock the account away from its own password.

sudo passwd linus

The characters you type stay off the screen, and I drove the whole exchange through an interactive terminal session so the captured frame is the session rather than a retyped copy of it. Expiring the password is a third command, and it turns a handed-over credential into one that has to be replaced at first login.

sudo passwd --expire linus
sudo chage -l linus

chage -l then reports the last change as password must be changed until the account holder does it. Reading the account back takes a few commands, and each one answers a different question.

  • getent passwd linus reports what the account row holds, including the home path and the shell
  • id linus reports the UID, the primary group, and every supplementary group
  • sudo passwd -S linus reports whether there is a usable password

The passwd command guide covers the locking and aging options, and listing all users in Ubuntu covers reading the whole account list back.

When useradd refuses

A handful of mistakes cover nearly every failure, and each one stops the command before it writes anything.

the three useradd refusals, a name that already exists, a uid that is not unique, and a group that does not exist
Each refusal stops before anything is written, and each one carries its own exit code
MessageExitCauseFix
user ‘linus’ already exists9the name is taken in the passwd file or a directory servicepick another name, or repair the account that holds it
UID 1002 is not unique4-u named a number already in useleave -u out, or pass -o when the duplicate is deliberate
group ‘nosuchteam’ does not exist6-G or -g named a group that is not therecreate the group first

The useradd manual page lists every exit code, and the ones worth knowing are 1 for a password file that could not be written, 2 for a syntax error, 3 for a bad argument, 10 for the group file, 12 for the home directory, 14 for SELinux, and 19 for a name that breaks the rules.

Exit 12 is the one to recognise in a provisioning script, because it means the account row was written and the home directory was not. An unwritable parent directory or a wrong SELinux context on the parent produces it.

The failures that print nothing are the ones worth guarding against, and the account from the first section is the example. It exists, it exits 0, and it cannot be logged into.

Repairing one is a two step job, because the flags that would have prevented it do not all work after the fact.

sudo usermod -s /bin/bash deploy
sudo mkhomedir_helper deploy
usermod -s changing the login shell and mkhomedir_helper creating the missing home directory at mode 0755
usermod fixes the shell field, while mkhomedir_helper is the command that creates the missing directory, and it uses 0755

usermod -s rewrites the shell field. The same command with -d and -m moves an existing home directory and does not create a missing one, which is why the second line is mkhomedir_helper instead.

mkhomedir_helper comes from the PAM packages, copies the skeleton, and leaves the mode at 0755 against the 0750 that HOME_MODE gives useradd -m. I ran both on the same half-built account and compared the two modes, and the difference held.

Deleting and recreating is the other repair, and it costs you the UID and everything the old account already owned.

A name that a directory service also holds is refused outright. Accounts kept in NIS or LDAP have to be created on the server that holds them.

Remove the account later

userdel takes the row back out, and -r decides whether the files go with it.

sudo userdel linus
sudo userdel -r linus
userdel -r reporting a missing mail spool, with getent and ls confirming the account and its home directory are gone
The mail spool line is a report rather than a failure, and the account and its home directory are both gone

The mail spool line is a report rather than a failure. CREATE_MAIL_SPOOL is set to no in /etc/default/useradd, so the file was never created, and userdel reports that rather than passing over it.

I ran userdel -r against an account whose home directory had never been created and got both warnings on one command, with an exit status of 0.

A logged-in account blocks its own removal, so end the sessions first.

loginctl terminate-user linus
sudo userdel -r linus

loginctl is the clean route where systemd is running. Killing the account’s own processes is the route that occasionally takes down the shell that typed the command.

The UID goes back into the pool the moment the account is gone, so the next account can be handed the same number.

Files the deleted account owned keep the old numeric owner, and a new account with the recycled UID inherits them. That is how a fresh account ends up owning another person’s files.

The next command to run

The check that closes the job costs one command, and it catches the failure this page opened with. I ran the same read-back on the demo account and it carries the UID, the primary group and the supplementary group on one line.

id linus

A UID, a primary group, a supplementary group for every name you passed to -G, and a home path you have confirmed exists on disk. Anything missing there means the account is half-built, and the login failure will arrive later and somewhere else.

That line belongs at the end of any provisioning script. A command that prints nothing and exits 0 is only trustworthy once something else has looked at the result.

FAQ

What does the useradd command do in Linux?

It writes the account rows in /etc/passwd, /etc/shadow and /etc/group using the defaults in /etc/default/useradd and /etc/login.defs. It writes only what the flags name, so a bare run leaves no home directory and a /bin/sh shell.

Why did useradd not create a home directory?

CREATE_HOME is commented out in /etc/login.defs on Ubuntu, so the default is off. Pass -m to create the directory and copy /etc/skel into it.

What is the difference between adduser and useradd?

On Debian and Ubuntu, adduser is a Perl wrapper that calls useradd with the missing flags and prompts for the password. On Fedora and RHEL the same name is a symbolic link to useradd, so explicit useradd flags are the portable choice.

How do I set the password for a user created with useradd?

Run sudo passwd followed by the account name. useradd leaves the account locked with an exclamation mark in /etc/shadow, and passwd -S shows that state as L until a password is set.

How do I add a user to a group with useradd?

Pass -G with a comma separated list of groups and create every one of them first. Use -g for the primary group instead, which is a different field with a different effect.

What does exit code 9 from useradd mean?

The username or group name is already in use. Nothing was written, so pick another name or repair the account that already holds it.