← Back

2026

Linux Users and Groups: Identity on the System

Every process has an identity. Every file has an owner. Users and groups are the foundation that access control is built on. Here is how Linux stores them, how to manage them and why service accounts exist.

Linux is a multi-user operating system. That statement gets repeated so often it stops meaning anything, but it is worth sitting with for a moment. From the kernel's perspective, every process running on the system has an identity. Every file has an owner. Every access decision, reading a file, opening a socket, writing a log, is made relative to that identity.

Users are not just human beings with login accounts. They are a security primitive. When you run nginx as www-data rather than root, you are using the user system to limit what a compromised process can touch. When a build pipeline writes artifacts to a directory and a deploy process reads from it, the group system is what lets both processes share access without giving everyone write permission.

This article covers how users and groups are stored on disk, the tools for managing them, how group membership actually takes effect at login time and how sudo fits into the picture.

/etc/passwd

Every user on a Linux system has a record in /etc/passwd. The file is plain text, world-readable and structured as colon-separated fields. One line per user. Despite the name, it has not stored passwords directly since the early days of Unix.

example entry
alice:x:1001:1001:Alice Smith:/home/alice:/bin/bash

username

The login name. This is the string you type at a prompt. It must be unique across the system.

password

Almost always an x on modern systems. The actual password hash lives in /etc/shadow, which only root can read.

UID

The numeric user ID. The kernel uses this number, not the name. Root is always 0. System accounts typically occupy 1 to 999. Regular users start at 1000.

GID

The numeric ID of the user's primary group. This is the group that new files get assigned to by default when the user creates them.

GECOS

A free-text comment field, traditionally used for the user's full name. Many tools display it as the display name. It is optional.

home directory

The absolute path to the user's home directory. This is where the shell starts after login and where user-specific config files live.

shell

The program that runs when the user logs in. For regular users this is typically /bin/bash. Service accounts often have /usr/sbin/nologin to block interactive login.

The kernel does not care about usernames. When a process checks ownership, it compares numeric UIDs. The name is a convenience for humans. This is why orphaned files owned by a deleted user's UID show up in ls -l as a raw number rather than a name.

/etc/shadow

Password hashes are stored in /etc/shadow, not in /etc/passwd. Shadow is readable only by root. This matters because /etc/passwd must be world-readable for tools like ls to translate UIDs to names. If hashes lived there too, any user on the system could attempt to crack them offline.

shadow entry structure

alice:$6$rounds=5000$salt$hash:19500:0:99999:7:::

The hash field starts with an identifier like $6$ for SHA-512 or $y$ for yescrypt. An exclamation mark at the start of the hash means the account is locked. A bare asterisk means no password is set and interactive password authentication is blocked entirely. The remaining fields control password ageing: minimum days before a change is allowed, maximum days before a change is required, warning period before expiry.

/etc/group

Groups are defined in /etc/group. Each line has four fields: the group name, a password placeholder (almost always an x), the GID and a comma-separated list of members.

example entries

docker:x:999:alice,bob

devs:x:2001:alice,carol,dave

ops:x:2002:bob

Users listed here are supplementary group members. The primary group is set in/etc/passwd and does not appear in the member list in /etc/group. When you add a user to a group with usermod -aG, this is the file being updated.

Group membership takes effect at login

When you add a user to a group, their running session does not pick it up immediately. The supplementary group list is read at login time and does not change until the user starts a new session. After adding a user to a group, they need to log out and back in. You can verify the current effective groups with id without arguments.

Managing users

The core tools are useradd, usermod and userdel. They write directly to /etc/passwd, /etc/shadow and/etc/group. On most distributions, adduser is also available as a friendlier wrapper around useradd with interactive prompts.

useradd -m -s /bin/bash alice

Create a new user named alice. -m creates the home directory. -s sets the login shell.

useradd -r -s /usr/sbin/nologin prometheus

Create a system account for a service. -r keeps the UID in the system range. nologin prevents interactive login.

passwd alice

Set or change the password for alice. Run as root to change any user's password. Run without a name to change your own.

usermod -aG docker alice

Add alice to the docker group without removing her from any existing groups. The -a flag is essential here. Omitting it replaces all supplementary groups.

usermod -s /usr/sbin/nologin alice

Change alice's login shell to nologin, effectively disabling interactive access without deleting the account.

usermod -L alice

Lock alice's account by prefixing her password hash with an exclamation mark. She cannot log in until unlocked with -U.

userdel -r alice

Delete alice's account. -r also removes her home directory and mail spool. Without -r, those files remain on disk owned by a now-orphaned UID.

The -aG combination in usermod deserves special attention. The -Gflag alone replaces the user's entire list of supplementary groups with whatever you specify. Forgetting -a is a common mistake that silently removes access the user already had. Always use them together.

Managing groups

Groups are created with groupadd and deleted with groupdel. The id command is the fastest way to inspect what groups a user currently belongs to.

groupadd devs

Create a new group named devs. The system assigns the next available GID automatically.

groupadd -g 2000 ops

Create the ops group with a specific GID. Useful when you need GIDs to match across multiple machines.

groupmod -n engineers devs

Rename the devs group to engineers. The GID does not change, so file ownership on disk is preserved.

groupdel devs

Delete the devs group. This will fail if devs is the primary group of any existing user.

groups alice

Print all groups alice belongs to, starting with her primary group.

id alice

Print alice's UID, primary GID and all supplementary group memberships by both name and number.

su and sudo

Two tools let you act as a different user without logging out. They have different security models and different use cases. On servers where root login over SSH is disabled, understanding both is essential.

susubstitutes the current user entirely. It authenticates using the target user's password. Once you are in, you have their full identity and environment. sudoruns a specific command with elevated privileges while authenticating using your own password. The distinction matters: sudo produces an audit trail tied to your account, not root's.

su - alice

Switch to alice's account with a full login shell. You get her environment, her home directory and her shell. Root can do this without a password. Everyone else is prompted.

su -

Switch to root with a full login environment. Equivalent to su - root.

sudo command

Run a single command as root, authenticated by your own password. Access is controlled by /etc/sudoers.

sudo -u alice command

Run a command as alice rather than root. Useful for testing what a specific user can do.

sudo -i

Open an interactive root shell using sudo. Similar to su - but authenticated as you, not as root.

sudo -l

List the sudo privileges your account has. Shows exactly which commands you are allowed to run.

/etc/sudoers

What each user is allowed to do with sudo is controlled by /etc/sudoers. Never edit this file directly with a text editor. Use visudo instead. It validates the syntax before saving, which prevents a broken sudoers file from locking you out of elevated access entirely.

common sudoers patterns
alice ALL=(ALL:ALL) ALL

Alice can run any command as any user on any host. The classic unrestricted sudo grant.

%sudo ALL=(ALL:ALL) ALL

Anyone in the sudo group gets the same unrestricted access. The % prefix means group.

alice ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx

Alice can restart nginx without entering a password. Useful for deploy scripts.

%ops ALL=(ALL) NOPASSWD: ALL

The ops group can run anything without a password. Common in automation environments where interactive prompts are not possible.

#includedir /etc/sudoers.d

Include all files in /etc/sudoers.d as additional rules. Distributions use this to let packages drop in their own entries cleanly.

Drop-in files in /etc/sudoers.d/ follow the same syntax as the main file. Keeping grants separated by purpose makes it much easier to audit who can do what. One file per service account is a reasonable convention.

Service accounts

Most daemons and background services run as dedicated system users rather than root. This is not just convention. It is how you limit the blast radius of a compromised process. A web server running as www-data can only touch files that www-data has permission to access. If an attacker exploits it, they land in a heavily restricted identity rather than one that owns the entire machine.

System accounts are created with useradd -r. They get UIDs in a reserved range below 1000 on most distributions. They have no home directory by default. Their shell is set to /usr/sbin/nologin so they cannot be used for interactive login even if someone finds a way to authenticate as them.

typical service account pattern
useradd -r -s /usr/sbin/nologin -d /var/lib/myapp -m myapp

Create a system account with a dedicated home directory under /var/lib. The service writes its data there.

chown -R myapp:myapp /var/lib/myapp /etc/myapp

Give the service account ownership of its data directory and config directory.

chmod 750 /etc/myapp

Restrict config directory access to the owner. Other users on the system cannot read service configuration.

Where it fits

Users and groups are the foundation that file permissions sit on top of. The permission bits on a file are meaningless without understanding who the kernel considers the owner, which group it belongs to and which identity the process accessing it is running under. These two systems are inseparable in practice.

In a production context, the user system appears everywhere. Systemd unit files have a User= directive that determines which account a service runs as. Container runtimes map UIDs between the host and the container. SSH authentication resolves to a system user. Cron jobs run as whichever user owns the crontab entry. Every one of these things is using the same underlying mechanism.

The recurring mistake in this area is giving services too much. A service does not need to be in the sudo group. It does not need write access to directories it only reads from. It does not need a real login shell. Applying the principle of least privilege through the user system is one of the most effective security controls available on Linux because it requires no additional software. It is already there.