15%

Save 15% on All Hosting Services

Test your skills and get Discount on any hosting plan

Use code:

Skills
Get Started
09.10.2024

useradd vs adduser: Technical Differences, Use Cases, and When to Use Each

`useradd` is a low-level binary utility available on virtually every Linux distribution that creates user accounts by directly writing to `/etc/passwd`, `/etc/shadow`, and `/etc/group`. `adduser` is a higher-level wrapper script — typically written in Perl on Debian-based systems — that calls `useradd` internally while automating home directory creation, skeleton file population, password prompting, and GECOS field collection. The practical difference is not just ergonomics: choosing the wrong tool in an automated provisioning pipeline or on a non-Debian system can silently produce incomplete user accounts.

Both commands ultimately register a user in the system's authentication database, but their behavior diverges significantly in defaults, interactivity, portability, and scriptability. This guide covers every technical distinction an administrator needs to make an informed decision.

What useradd Actually Does Under the Hood

`useradd` is part of the shadow-utils package (sometimes called `passwd` on older distributions). When invoked, it performs a series of atomic operations:

  1. Reads `/etc/login.defs` to determine default UID ranges, password aging policies, and whether to create a home directory by default.
  2. Reads `/etc/default/useradd` for default shell, skeleton directory path, and group behavior.
  3. Writes a new entry to `/etc/passwd` and `/etc/shadow`.
  4. Optionally creates a home directory and copies files from `/etc/skel` if `-m` is explicitly passed.
  5. Optionally creates a private group matching the username if `USERGROUPS_ENAB` is set to `yes` in `/etc/login.defs`.

A critical point many guides omit: on Red Hat-based distributions (RHEL, CentOS, Rocky Linux, AlmaLinux), `useradd` creates the home directory by default because `/etc/login.defs` sets `CREATE_HOME yes`. On Debian and Ubuntu, it does not — the `-m` flag is mandatory unless you modify `/etc/default/useradd`. This behavioral asymmetry is a frequent source of confusion when administrators migrate between distribution families.

Key Flags and Their Behavior

FlagPurposeNotes
———————-
`-m`Create home directoryRequired on Debian/Ubuntu without config change
`-d /path`Set custom home directory pathDoes not create the directory unless `-m` is also used
`-s /bin/bash`Set login shellDefaults to `/bin/sh` or value in `/etc/default/useradd`
`-u UID`Assign specific UIDMust be unique; use `-o` to allow duplicates
`-g GID`Set primary groupGroup must already exist
`-G group1,group2`Add supplementary groupsComma-separated, no spaces
`-e YYYY-MM-DD`Account expiration dateWritten to `/etc/shadow` field 8
`-f days`Password inactivity periodDays after expiry before account is locked
`-r`Create system accountUID below `SYS_UID_MAX` in `/etc/login.defs`, no home directory by default
`-M`Explicitly do not create home directoryOverrides distro defaults
`-N`Do not create a user private groupUser's primary group becomes the default group
`-k /path`Specify alternative skeleton directoryOverrides `/etc/skel`

Practical useradd Example with Full Options

“`bash

useradd

-m

-d /srv/appuser

-s /bin/bash

-u 1500

-g developers

-G sudo,docker

-e 2025-12-31

-c "Application Service Account"

appuser

passwd appuser

“`

No password is set until `passwd` is called. Until then, the account exists but is locked — the shadow entry contains `!` as the password hash, preventing login via password authentication. SSH key-based login, however, is unaffected by this state.

What adduser Actually Does Under the Hood

On Debian and Ubuntu, `adduser` is a Perl script located at `/usr/sbin/adduser`. It reads its own configuration from `/etc/adduser.conf` — a separate file from `/etc/login.defs` — and then calls `useradd` with the appropriate flags based on that configuration plus user input.

The script performs additional steps that `useradd` alone does not:

  • Prompts interactively for a password and confirms it with a second entry.
  • Collects GECOS fields (full name, room number, work phone, home phone, other) via guided prompts.
  • Copies skeleton files from `/etc/skel` automatically without requiring `-m`.
  • Sets correct ownership and permissions on the home directory.
  • Optionally adds the user to supplementary groups defined in `/etc/adduser.conf`.

On Red Hat-based systems, `adduser` is typically a symlink to `useradd`, meaning it behaves identically to the low-level binary — there is no interactive wrapper. This is the single most important portability issue when writing cross-distribution scripts.

adduser Configuration File: /etc/adduser.conf

Key directives in `/etc/adduser.conf` that affect behavior:

“`

DSHELL=/bin/bash # Default shell

DHOME=/home # Parent directory for home directories

GROUPHOMES=no # Whether to create group-named subdirectories

LETTERHOMES=no # Whether to use first-letter subdirectories

USERGROUPS=yes # Create a group with the same name as the user

USERS_GID=100 # Default GID if USERGROUPS=no

DIR_MODE=0755 # Permissions on new home directories

SETGID_HOME=no

QUOTAUSER=""

SKEL=/etc/skel

SKEL_IGNORE_REGEX="dpkg-(old|new|dist|tmp)"

“`

Modifying this file lets you standardize user creation across a fleet of Debian/Ubuntu servers without passing flags every time.

Practical adduser Example

“`bash

adduser customuser

“`

The interactive session looks like this:

“`

Adding user 'customuser' …

Adding new group 'customuser' (1001) …

Adding new user 'customuser' (1001) with group 'customuser' …

Creating home directory '/home/customuser' …

Copying files from '/etc/skel' …

New password:

Retype new password:

passwd: password updated successfully

Changing the user information for customuser

Enter the new value, or press ENTER for the default

Full Name []: Jane Smith

Room Number []:

Work Phone []:

Home Phone []:

Other []:

Is the information correct? [Y/n] Y

“`

To add an existing user to a group non-interactively with `adduser`:

“`bash

adduser customuser sudo

“`

This is a notable feature: `adduser` doubles as a group membership management tool, which `useradd` does not replicate in a single command.

Side-by-Side Comparison

Feature`useradd``adduser`
TypeBinary (C program)Script (Perl on Debian, symlink on RHEL)
InteractivityNon-interactive; all options via flagsInteractive prompts by default
Home directoryNot created unless `-m` is passed (Debian)Created automatically
Password setupRequires separate `passwd` commandPrompted during creation
GECOS fieldsSet via `-c` flag as a single stringCollected field-by-field interactively
Skeleton filesCopied only with `-m` flagAlways copied
Config file`/etc/login.defs`, `/etc/default/useradd``/etc/adduser.conf`
Cross-distro availabilityAll Linux distributionsDebian/Ubuntu only (as a wrapper script)
Scripting suitabilityExcellent — fully non-interactivePoor — requires `–disabled-password` and `–gecos` flags to avoid prompts
System accountsSupported via `-r` flagSupported via `–system` flag
Group managementOnly at creation timeCan add user to existing group post-creation
GranularityFull control over every parameterOpinionated defaults, less granular

When to Use useradd

Automation and Infrastructure-as-Code

`useradd` is the correct choice in any non-interactive context: Ansible playbooks, Terraform provisioners, Docker `RUN` instructions, cloud-init scripts, and CI/CD pipelines. It produces deterministic output with no stdin dependency.

“`bash

Ansible task equivalent

useradd -m -s /bin/bash -G sudo -c "Deploy User" deployuser

echo "deployuser:$(openssl passwd -6 'securepassword')" | chpasswd

“`

Cross-Distribution Portability

Any shell script intended to run on both Debian-based and RHEL-based systems must use `useradd`. Relying on `adduser` behavior will produce silent failures or unexpected behavior on CentOS, Fedora, Rocky Linux, or Alpine Linux.

System and Service Accounts

Creating locked, no-login service accounts for daemons is a `useradd` specialty:

“`bash

useradd -r -s /usr/sbin/nologin -d /var/lib/myservice -m myservice

“`

The `-r` flag assigns a UID below the system account threshold, signals to administrators that this is not a human user account, and is the standard pattern for application deployment on VPS Hosting environments where service isolation is critical.

Precise UID/GID Control

In NFS environments, container orchestration, or when synchronizing user databases across multiple servers, consistent UIDs and GIDs are mandatory. `useradd -u 1500 -g 1500` guarantees this; `adduser` does not offer the same deterministic control without significant configuration.

When to Use adduser

Interactive Server Setup

When provisioning a new Dedicated Server manually and adding the first few human user accounts, `adduser` reduces the risk of incomplete setup. The guided prompts make it nearly impossible to forget the password step.

Debian/Ubuntu Environments with Standard Defaults

If your entire infrastructure runs Debian or Ubuntu and you are creating standard home-directory users, `adduser` produces correct results faster with fewer flags to remember.

Post-Creation Group Management

The `adduser username groupname` syntax for adding an existing user to an existing group is cleaner than `usermod -aG groupname username`, though both are valid.

Onboarding Junior Administrators

The interactive nature of `adduser` makes it a better teaching tool. It surfaces the fields that matter (password, full name) and hides the complexity of UID ranges and skeleton directories until the administrator is ready to learn them.

Critical Edge Cases and Pitfalls

The Missing Home Directory Trap

On Debian/Ubuntu, running `useradd username` without `-m` creates the user but not the home directory. The user can log in (once a password is set), but `$HOME` will not exist, causing failures in any application that writes to the home directory on first login — including `.bash_history`, `.ssh/authorized_keys`, and many application config directories.

“`bash

Verify home directory existence after creation

ls -la /home/newuser || echo "Home directory missing — run: mkhomedir_helper newuser"

“`

Shadow File Locking

Both commands lock `/etc/shadow` during writes. In high-concurrency provisioning scripts creating dozens of users simultaneously, this causes race conditions. Use a queue or sequential execution when bulk-creating users.

UID Collision in Containerized Environments

When deploying applications on VPS with cPanel or other control panel environments, the panel itself manages UID allocation. Running `useradd` manually with a hardcoded UID can collide with panel-assigned UIDs, causing permission errors across multiple accounts. Always check `getent passwd | awk -F: '{print $3}' | sort -n` before specifying a UID manually.

adduser –disabled-password for Scripting

If you must use `adduser` in a script (for example, to leverage its `/etc/adduser.conf` defaults), suppress the interactive prompts:

“`bash

adduser –disabled-password –gecos "Automated User,,," scriptuser

echo "scriptuser:$(openssl passwd -6 'password')" | chpasswd

“`

The `–gecos` flag accepts a comma-separated string matching the GECOS fields, eliminating all interactive prompts.

PAM and NSS Integration

Neither `useradd` nor `adduser` configures PAM modules or NSS (Name Service Switch) entries for LDAP, Active Directory, or other centralized authentication systems. On servers integrated with `sssd` or `winbind`, local user creation with either command creates accounts that may conflict with or be superseded by directory service accounts. Verify `/etc/nsswitch.conf` before creating local users on domain-joined systems.

Skeleton File Customization

Both commands copy from `/etc/skel` by default. For teams managing Shared Web Hosting environments where each user needs a pre-configured `.bashrc`, `.vimrc`, or SSH config, populating `/etc/skel` before running either command is the correct approach — not modifying files after account creation.

Verifying User Creation

Regardless of which command you use, verify the result:

“`bash

Check passwd entry

getent passwd newuser

Check shadow entry (requires root)

getent shadow newuser

Check group memberships

groups newuser

id newuser

Verify home directory and permissions

ls -la /home/newuser

Test login shell

su -s /bin/bash – newuser -c "echo login successful"

“`

Modifying and Deleting Users

`useradd` and `adduser` only create accounts. Post-creation management uses different commands:

  • `usermod` — Modify existing user attributes (shell, groups, home directory, expiry).
  • `userdel` / `deluser` — Remove accounts. `deluser –remove-home username` on Debian also removes the home directory and mail spool.
  • `passwd` — Set or change passwords, lock/unlock accounts.
  • `chage` — Manage password aging and expiration policies.

“`bash

Lock an account without deleting it

usermod -L username

Unlock

usermod -U username

Force password change on next login

chage -d 0 username

“`

Practical Decision Matrix

Use this checklist to select the right command:

  • Is the script running on a non-Debian system or needs to be portable? Use `useradd`.
  • Is this an automated, non-interactive environment (CI/CD, Ansible, Docker)? Use `useradd`.
  • Do you need a specific UID/GID for NFS or container consistency? Use `useradd -u -g`.
  • Are you creating a system/service account with no login shell? Use `useradd -r -s /usr/sbin/nologin`.
  • Are you on Debian/Ubuntu, creating a standard human user account interactively? Use `adduser`.
  • Do you want to add an existing user to a group with a clean one-liner? Use `adduser username groupname`.
  • Are you writing documentation or training junior staff on Debian? Use `adduser`.
  • Do you need to customize home directory location, expiry, or shell non-interactively at scale? Use `useradd` with explicit flags.

Proper user account hygiene is foundational to server security. Whether you are managing a single VPS or a fleet of Dedicated Servers, understanding exactly what each command writes to disk — and what it leaves unset — prevents the class of privilege escalation and authentication failures that stem from incomplete account provisioning.

FAQ

Does useradd create a home directory by default?

It depends on the distribution. On Red Hat-based systems (RHEL, CentOS, Rocky Linux), `CREATE_HOME yes` in `/etc/login.defs` causes `useradd` to create the home directory automatically. On Debian and Ubuntu, no home directory is created unless you explicitly pass the `-m` flag.

Is adduser available on CentOS or Rocky Linux?

On RHEL-based distributions, `adduser` is a symbolic link to `useradd`, not the interactive Perl wrapper found on Debian/Ubuntu. Running `adduser username` on CentOS behaves identically to `useradd username` — no prompts, no automatic home directory on Debian-style defaults.

How do I use adduser non-interactively in a script?

Pass `–disabled-password` to skip the password prompt and `–gecos ""` to skip the GECOS field prompts: `adduser –disabled-password –gecos "" username`. Set the password afterward with `echo "username:password" | chpasswd` or by piping an `openssl passwd -6` hash.

What is the difference between /etc/login.defs and /etc/adduser.conf?

`/etc/login.defs` is the system-wide configuration file read by `useradd`, `userdel`, and `usermod` — it controls UID/GID ranges, password aging defaults, and home directory creation behavior. `/etc/adduser.conf` is read exclusively by the `adduser` and `deluser` Perl scripts on Debian-based systems and controls higher-level defaults like the default shell, home directory parent path, and skeleton directory.

Can I safely mix useradd and adduser on the same Debian server?

Yes. Both ultimately write to the same `/etc/passwd`, `/etc/shadow`, and `/etc/group` files. Accounts created with either command are indistinguishable at the system level. The only practical concern is consistency: if your team uses `adduser` interactively and an automation script uses `useradd` without `-m`, you may end up with some users missing home directories. Standardize on one approach per environment and document it.

15%

Save 15% on All Hosting Services

Test your skills and get Discount on any hosting plan

Use code:

Skills
Get Started