Linux User and Group Management: Complete Guide

Linux User and Group Management: Complete Guide

Tested on: Ubuntu 26.04 LTS · Debian 12 · Rocky Linux 10 · Arch Linux — Last updated: June 2026

Every process on Linux runs as a user, every file has an owner, and access control flows entirely from users and groups. Getting this right is foundational — mistakes here cascade into security holes, broken services, and permission nightmares. This guide covers the full lifecycle: creating and modifying users, managing groups, reading /etc/passwd and /etc/shadow, configuring sudo, locking accounts, creating proper service accounts, and handling bulk operations. All commands are cross-distro unless noted.

Contents
  1. Prerequisites
  2. User and Group Concepts
  3. The /etc/passwd, /etc/shadow, and /etc/group Files
  4. Creating Users
    1. useradd vs adduser
  5. Modifying Users
  6. Deleting Users
  7. Password Management
  8. Group Management
  9. sudo Configuration
  10. Switching Users
  11. Locking and Expiring Accounts
  12. Service Accounts
    1. Further Reading

Prerequisites

  • Root or sudo access on the target system
  • Familiarity with basic terminal usage and file paths
  • For the sudo section: the sudo package must be installed (apt install sudo or dnf install sudo)

User and Group Concepts

Before touching commands, the data model matters:

  • UID (User ID): A unique numeric identifier for each user. Root is always 0. System/service accounts occupy 1–999 (or 1–499 on older RHEL). Regular human users start at 1000.
  • GID (Group ID): Numeric ID for each group. By default, useradd creates a private group with the same name and GID as the user.
  • Primary group: Recorded in /etc/passwd. New files created by the user inherit this group.
  • Supplementary groups: Additional group memberships listed in /etc/group. Used to grant access to shared resources (Docker socket, sudo, www-data directories, etc.).
  • Home directory: Defaults to /home/username for humans. Service accounts typically use /var/lib/servicename or no home at all.

The /etc/passwd, /etc/shadow, and /etc/group Files

/etc/passwd is world-readable and stores account metadata. /etc/shadow is root-only and stores password hashes. Never edit these directly — use the tools below.

# /etc/passwd — seven colon-separated fields:
# username:x:UID:GID:GECOS(comment):home:shell
cat /etc/passwd | grep alice
# alice:x:1001:1001:Alice Smith:/home/alice:/bin/bash
# 'x' means the hash lives in /etc/shadow

# /etc/shadow — root-readable only:
# username:hash:lastchange:mindays:maxdays:warndays:inactive:expire:reserved
sudo grep alice /etc/shadow
# alice:$6$rounds=656000$sABC...xyz:19878:0:99999:7:::
# Hash starts with $6$ = SHA-512. $y$ = yescrypt (Ubuntu 24.04+). $5$ = SHA-256.

# /etc/group — group membership:
# groupname:x:GID:member1,member2,...
grep docker /etc/group
# docker:x:998:alice,bob

# getent queries NSS (handles LDAP/NIS too, not just flat files):
getent passwd alice
getent group developers

Creating Users

# Minimal: create user with home directory and bash shell:
sudo useradd -m -s /bin/bash alice

# Full options — the way you'd do it in production:
sudo useradd 
  -m                           # create home directory from /etc/skel
  -s /bin/bash                 # login shell
  -c "Alice Smith"             # GECOS / full name
  -u 1500                      # specific UID (optional — auto-assigned if omitted)
  -g developers                # primary group (must exist)
  -G sudo,docker,www-data      # supplementary groups (comma-separated, no spaces)
  alice

# Set password immediately:
sudo passwd alice

# Verify:
id alice
# uid=1500(alice) gid=1001(developers) groups=1001(developers),27(sudo),998(docker),33(www-data)

getent passwd alice
# alice:x:1500:1001:Alice Smith:/home/alice:/bin/bash

useradd vs adduser

On Debian and Ubuntu, adduser is an interactive Perl script that wraps useradd — it asks for a password, full name, and other details, then copies skeleton files automatically. It is friendlier for one-off manual account creation. On RHEL, Rocky, and Fedora, adduser is a symlink to useradd and behaves identically. For any automation or scripting, always use useradd directly to keep behavior predictable and avoid interactive prompts.

# Debian/Ubuntu interactive creation:
sudo adduser alice

# Non-interactive useradd for scripts — set password via chpasswd:
sudo useradd -m -s /bin/bash -c "Alice Smith" alice
echo "alice:$(openssl rand -base64 16)" | sudo chpasswd

Modifying Users

# Change login shell:
sudo usermod -s /bin/zsh alice

# Change home directory AND move existing files there:
sudo usermod -m -d /srv/home/alice alice

# Change primary group:
sudo usermod -g newprimarygroup alice

# Add to supplementary group — ALWAYS use -aG (append + group):
sudo usermod -aG docker alice
sudo usermod -aG sudo,video alice

# WARNING: omitting -a replaces ALL supplementary groups:
# sudo usermod -G docker alice  <-- alice loses sudo, www-data, everything else

# Rename the account (username only — home directory path does NOT change automatically):
sudo usermod -l alicesmith alice
# Then update the home path too:
sudo usermod -d /home/alicesmith -m alicesmith

# Change UID (fixes ownership issues when migrating between servers):
sudo usermod -u 1500 alice

# Update GECOS comment field:
sudo usermod -c "Alice M. Smith, Engineering" alice

# Confirm all changes:
id alice
grep alice /etc/passwd

Deleting Users

# Remove account but keep home directory and mail spool:
sudo userdel alice

# Remove account AND home directory AND mail spool:
sudo userdel -r alice

# Before deleting, audit what the user owns across the filesystem:
sudo find / -user alice 2>/dev/null
# If the account is already gone, search by UID:
sudo find / -uid 1001 2>/dev/null

# Transfer orphaned files to another user before deleting:
sudo find / -user alice -exec chown bob:bob {} ;

# Check for running processes owned by the user:
ps -u alice

Password Management

# Set password interactively:
sudo passwd alice

# Set password non-interactively (scripts, provisioning):
echo "alice:S3cur3P@ssw0rd" | sudo chpasswd

# Force password change at next login:
sudo passwd -e alice
# or equivalently:
sudo chage -d 0 alice

# Set a full password aging policy:
sudo chage -M 90 alice    # password expires after 90 days
sudo chage -m 1 alice     # minimum 1 day before password can be changed again
sudo chage -W 14 alice    # warn user 14 days before expiry
sudo chage -I 7 alice     # lock account 7 days after expiry with no change

# View current aging configuration:
sudo chage -l alice
# Example chage -l output:
Last password change                                    : Jun 01, 2026
Password expires                                        : Aug 30, 2026
Password inactive                                       : Sep 06, 2026
Account expires                                         : never
Minimum number of days between password change          : 1
Maximum number of days between password change          : 90
Number of days of warning before password expires       : 14
# Lock password (disables password auth — SSH key login still works):
sudo passwd -l alice

# Unlock:
sudo passwd -u alice

# Check password status:
sudo passwd -S alice
# alice L 2026-06-01 1 90 14 7
# Status codes: P=active, L=locked, NP=no password

Group Management

# Create a group:
sudo groupadd developers

# Create with a specific GID (useful for consistency across servers):
sudo groupadd -g 2000 developers

# Add user to a group:
sudo usermod -aG developers alice

# Remove user from a group:
sudo gpasswd -d alice developers

# List all members of a group:
getent group developers
# developers:x:2000:alice,bob,charlie

# List all groups a user belongs to:
groups alice
id alice

# Rename a group:
sudo groupmod -n engineering developers

# Change a group's GID:
sudo groupmod -g 2500 developers

# Delete a group (fails if it's anyone's primary group):
sudo groupdel developers

# Switch primary group for the current shell session only:
newgrp developers
# Files created after this command belong to 'developers' group

Note on group changes taking effect: After adding a user to a group with usermod -aG, the change is written immediately to /etc/group, but the user's running processes still hold the old token. The user must log out and back in (or start a new session with newgrp groupname or su - username) before the new membership is visible to their processes.

sudo Configuration

The /etc/sudoers file must only ever be edited with visudo, which validates syntax before saving. A syntax error in sudoers locks out all sudo access — on a remote server, that can be unrecoverable without console access.

# Grant sudo via group membership (preferred for most use cases):
sudo usermod -aG sudo alice       # Debian/Ubuntu
sudo usermod -aG wheel alice      # RHEL/Rocky/Fedora/Arch

# Edit sudoers (always use visudo):
sudo visudo
# /etc/sudoers examples — paste inside visudo:

# Full sudo for a user:
alice ALL=(ALL:ALL) ALL

# Full sudo without password prompt (CI runners, automation accounts):
alice ALL=(ALL:ALL) NOPASSWD: ALL

# Specific commands only (principle of least privilege):
alice ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx

# Group-based sudo (% prefix = group):
%developers ALL=(ALL:ALL) ALL
%wheel ALL=(ALL) NOPASSWD: ALL

# Run commands as a specific non-root user:
alice ALL=(deploy) /usr/bin/git pull, /usr/bin/git status
# Drop-in files in /etc/sudoers.d/ are safer than editing the main file:
echo "alice ALL=(ALL:ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/alice
sudo chmod 440 /etc/sudoers.d/alice

# Validate without applying (dry-run):
sudo visudo -c -f /etc/sudoers.d/alice
# parsed OK

Switching Users

# Switch to another user — keeps current environment variables:
su alice

# Switch with a full login environment (loads their .bashrc, .profile, PATH):
su - alice

# Run a single command as another user:
su -c "whoami && env | grep HOME" - alice

# Switch to root:
su -
sudo su -

# Run a command as a specific user via sudo:
sudo -u alice whoami
sudo -u www-data php /var/www/html/artisan cache:clear

# Open an interactive shell as another user via sudo:
sudo -u alice -s /bin/bash
sudo -u alice -i    # login shell equivalent of su -

Locking and Expiring Accounts

passwd -l only disables password authentication — SSH key login remains possible. usermod -L does the same. To block all access including SSH keys, set the account expiry date or change the shell to /usr/sbin/nologin.

# Lock password (SSH keys still work):
sudo passwd -l alice
sudo usermod -L alice    # equivalent

# Unlock:
sudo passwd -u alice
sudo usermod -U alice

# Set account expiry date (blocks ALL logins including SSH keys):
sudo usermod -e 2026-12-31 alice
sudo chage -E 2026-12-31 alice    # same result

# Expire immediately (immediate lockout):
sudo usermod -e 1 alice

# Remove expiry date (restore access):
sudo usermod -e "" alice
sudo chage -E -1 alice

# Disable login by setting shell to nologin (also blocks SSH keys):
sudo usermod -s /usr/sbin/nologin alice

# Check lock status:
sudo passwd -S alice
# alice L 2026-06-01 0 99999 7 -1
# L = locked, P = password set, NP = no password

Service Accounts

Services must not run as root. Create a dedicated system user with no home directory, no valid shell, and no password. Pin the UID if you need consistent ownership across multiple servers (containers, NFS mounts).

# Standard service account creation:
sudo useradd
--system
--no-create-home
--shell /usr/sbin/nologin
--comment "MyApp service account"
myapp

# With a pinned UID and a matching system group:
sudo groupadd --system --gid 488 myapp
sudo useradd
--system
--uid 488
--gid 488
--no-create-home
--shell /usr/sbin/nologin
myapp

# Create and set ownership of runtime directories:
sudo mkdir -p /var/lib/myapp /var/log/myapp /run/myapp
sudo chown -R myapp:myapp /var/lib/myapp /var/log/myapp /run/myapp
sudo chmod 750 /var/lib/myapp /var/log/myapp
sudo chmod 755 /run/myapp

# Verify the account cannot be used for interactive


Go up

This site uses cookies for analytics and advertising (Google AdSense). By continuing to browse, you accept our use of cookies. Learn more