DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel
Explore NY Stream

How to Manage Users and Groups on Linux

— ny_wk

How to Manage Users and Groups on Linux

Managing users and groups on Linux means creating accounts with useradd, organizing them with groupadd, controlling membership with usermod, and securing access through passwords, account locking, and login policies. This guide walks through every step a system administrator needs, from creating a group to disabling a service account, with correct, runnable commands you can trust.

Every command below targets modern Linux distributions (RHEL/Rocky/AlmaLinux 8+, Ubuntu, Debian) and is run as root or with sudo. The same skills are also a staple of Linux system administration interviews, so the reasoning behind each command is explained, not just the syntax.

Why Linux user and group management matters

On a Linux system, every file, process, and resource is owned by a user and a group. Getting accounts and group membership right is the foundation of the permission model: it decides who can read a database directory, run a deployment script, or restart a service. Sloppy account hygiene is one of the most common root causes of both outages and security incidents.

Three command families do almost all the work:

  • useradd / usermod / userdel — create, modify, and remove user accounts.
  • groupadd / groupmod / groupdel — manage groups.
  • passwd / chage / faillock — manage passwords, aging, and lockouts.

Creating groups the right way

A group bundles users so you can grant a permission once and apply it to everyone in the group. Before creating a group, confirm the name and the numeric GID (group ID) are not already in use, especially in a fleet where GIDs should stay consistent across servers (a file owned by GID 1690 must mean the same group everywhere, or NFS and backups break).

Check whether a group already exists:

  1. Search the local group database for the name:
    getent group fadev
    This returns a line if the group exists, or nothing if it does not. getent is better than reading /etc/group directly because it also consults LDAP, SSSD, or NIS.
  2. List the next free GID in a chosen range so you can keep numbering predictable:
    getent group | awk -F: '$3>=1000 && $3<60000 {print $3}' | sort -n | tail -1
  3. Create the group with an explicit GID so it matches across the fleet:
    groupadd -g 1690 fadev

If you do not care about the exact number, just run groupadd fadev and the system assigns the next available GID automatically. Use a system group (low GID, for services) with the -r flag:

  • groupadd -r appsvc — creates a system group, typically below GID 1000.

A note on legacy syntax: on older AIX systems the command was mkgroup -A id=1706 sas. On Linux the correct command is always groupaddmkgroup does not exist there. If you maintain mixed environments, keep the two clearly separated and never copy an AIX line onto a Linux host.

Removing a group

Delete a group with groupdel:

  • groupdel fadev

You cannot delete a group that is still the primary group of any user — reassign those users first (shown below). Files still owned by the deleted GID will display a bare number instead of a name, so audit ownership before removing a group that owned data:

  • find / -gid 1690 -ls 2>/dev/null

Managing group membership with usermod

This is where most mistakes happen, because the difference between a few flags is the difference between adding a user and accidentally wiping all their group memberships.

GoalCommandEffect
Change primary groupusermod -g operator bgatesReplaces the user's primary group
Set secondary groupsusermod -G faadm,fadev bgatesReplaces ALL secondary groups
Add a secondary groupusermod -aG faadm bgatesAppends without removing existing

The critical rule: always use -a together with -G when adding a user to a group. Running usermod -G fadev bgates without -a removes the user from every other secondary group — a classic way to lock someone out of sudo or docker. The safe, almost-always-correct command is:

  • usermod -aG fadev bgates

Verify the result immediately:

  • id bgates — shows UID, primary GID, and all secondary groups.
  • groups bgates — lists group names only.

Group changes take effect on the user's next login (or new shell), not in their current session.

Creating users on Linux

Before creating an account, settle two things: the username and the UID (user ID). In a managed environment the username should match the corporate identity (the same login the person uses elsewhere), and if the user already has a UID on other hosts, reuse that exact UID so file ownership stays consistent across the fleet.

Create a user with a full set of common options:

  1. Run useradd with an explicit UID, primary group, comment (GECOS / full name), shell, and home directory:
    useradd -u 1457 -g fadev -c 'Peter Filipowich' -s /bin/bash -m -d /home/pfilipo pfilipo
  2. The flags mean:
    • -u 1457 — the numeric UID.
    • -g fadev — the primary group (must already exist).
    • -c 'Peter Filipowich' — the comment/full-name field.
    • -s /bin/bash — the login shell. (Many older shops standardized on /bin/ksh; /bin/bash is the modern default.)
    • -m -d /home/pfilipo — create the home directory at this path. Add -m; without it the directory is often not created and the user logs into /.
  3. Set an initial password:
    passwd pfilipo
  4. Force a password change at first login (Linux does not do this by default):
    chage -d 0 pfilipo

To add secondary groups during creation, append -G:

  • useradd -u 1457 -g fadev -G faadm,wheel -c 'Peter Filipowich' -s /bin/bash -m pfilipo

Functional and service accounts

A functional ID (shared/service account) should be documented and locked down so it cannot be used for interactive login. Record the human owner in the comment field, then disable shell access and password expiry:

  1. Create it with a descriptive comment naming the owner:
    useradd -u 911 -g db2sys -c 'Service ID for MS, owner: Mark Liu' -s /sbin/nologin -m mssvc
  2. Disable password aging so the account does not expire:
    chage -M -1 mssvc
  3. Ensure interactive login is blocked — /sbin/nologin politely refuses logins; /bin/false simply exits:
    usermod -s /sbin/nologin mssvc

Prefer /sbin/nologin over /bin/false for service accounts: it prints a clear message and supports a custom /etc/nologin.txt notice, which helps when someone troubleshoots a failed login.

Removing users

Decide whether to keep the home directory. Removing the account but keeping the data:

  • userdel bgates

Removing the account and its home directory and mail spool:

  • userdel -r bgates

Best practice for offboarding: lock the account first, confirm no critical processes or cron jobs run as that user, then delete. Search for files the user owns elsewhere before deleting, so orphaned data is not left behind:

  • find / -user bgates -ls 2>/dev/null

Locking, unlocking, and disabling accounts

Locking disables password authentication without deleting the account — ideal for suspensions or offboarding.

  • Lock: usermod -L bgates (puts a ! in front of the password hash in /etc/shadow).
  • Unlock: usermod -U bgates.
  • Lock and set an expiry date in one step: usermod -L -e 1 bgates (also blocks key-based and other auth that honors account expiry).

Important nuance: usermod -L only disables the password. A user with an authorized SSH key can still log in. To fully disable an account, also expire it with chage -E 0 bgates or remove the login shell.

Checking account status

Two independent things can block a login: the password being locked, and the failed-login counter exceeding its limit. Check both.

  1. Password and aging status:
    passwd -S bgates
    Typical output: bgates LK 2010-03-17 0 35 14 0 (Password locked.) — the LK token means the password is locked; PS/P means a usable password is set; NP means no password.
  2. Full aging detail (expiry, last change, warning days):
    chage -l bgates
  3. Failed-login lockout status. Modern RHEL/Fedora uses pam_faillock:
    faillock --user bgates
    On Debian/Ubuntu with pam_tally2, use pam_tally2 --user bgates. The old faillog tool only works where pam_tally/faillog is configured and is largely deprecated.

If either the password is locked or the failure counter is over the limit, the account will refuse logins — so always check both.

Resetting passwords and clearing lockouts

To reset a password and force the user to choose a new one at next login:

  1. Set the new password: passwd bgates
  2. Force a change at next login: chage -d 0 bgates

To clear a failed-login lockout on a modern system, reset the faillock counter:

  • faillock --user bgates --reset

This is the current, supported replacement for the old faillog -r -u command. (The historical Red Hat bug where faillog -r appeared to hang has been gone for years; on legacy systems you could interrupt with Ctrl-C, but on supported releases use faillock --reset instead.)

Preventing shell login

To stop an existing user from getting an interactive shell — without deleting them — change their shell:

  • usermod -s /sbin/nologin bgates

This is the standard way to convert a former interactive account into a non-login service account, or to park an account that still needs to own files and run scheduled jobs but should never be logged into directly.

Common pitfalls to avoid

  • Forgetting -a with -G — the single most damaging mistake; it silently strips all other secondary groups.
  • Forgetting -m with useradd — the home directory is not created and login behaves strangely.
  • Inconsistent UIDs/GIDs across servers — breaks NFS, backups, and rsync ownership. Reuse the same numeric IDs fleet-wide.
  • Relying on usermod -L alone — it does not block SSH-key logins; also expire or change the shell.
  • Editing /etc/passwd or /etc/shadow by hand — use vipw/vigr if you must, so the files stay locked and consistent.
  • Using AIX commands (mkgroup, mkuser) on Linux — they do not exist; use groupadd/useradd.

Verification checklist

After any change, confirm the result rather than assuming success:

  1. id username — UID, primary group, and all secondary groups are correct.
  2. getent passwd username — home directory and shell are what you intended.
  3. getent group groupname — the group exists with the expected GID and members.
  4. passwd -S username and chage -l username — password and aging status are correct.
  5. su - username (for interactive accounts) — a real login test that lands in the right home directory.

Key Takeaways

  • Use useradd -m to create users and always set a password with passwd, then force a change with chage -d 0.
  • Always combine -a and -G (usermod -aG group user) so you append group membership instead of replacing it.
  • Keep UIDs and GIDs consistent across every server to protect file ownership over NFS and backups.
  • Lock and expire together (usermod -L plus chage -E 0) to truly disable an account, since locking the password alone does not stop SSH keys.
  • Verify everything with id, getent, and passwd -S — never assume a change applied.

Frequently Asked Questions

What is the difference between useradd and adduser?

useradd is the low-level binary present on every Linux system and is fully scriptable. adduser is a higher-level, interactive Perl wrapper found mainly on Debian/Ubuntu that prompts for a password and creates the home directory for you. For automation and portability across distributions, prefer useradd.

How do I add a user to the sudo group?

On Debian/Ubuntu run usermod -aG sudo username; on RHEL, Rocky, AlmaLinux, and Fedora run usermod -aG wheel username. The user must log out and back in for the new group to take effect, after which sudo commands will work.

How can I see all the groups a user belongs to?

Run id username for UID, primary group, and every secondary group, or groups username for just the group names. To list members of a specific group, use getent group groupname.

What is the difference between locking a user and deleting a user?

Locking with usermod -L disables password login but keeps the account, its UID, home directory, and file ownership intact, so it is fully reversible — ideal for suspensions. Deleting with userdel (or userdel -r to remove the home directory) permanently removes the account; reuse of the same UID later can cause confusing ownership on leftover files.

For more hands-on Linux and system administration walkthroughs, subscribe to our YouTube channel @explorenystream.