Users and Groups Concepts
Every process on a Linux system runs as some user, and every user belongs to at least one group. This isn’t just bookkeeping — it’s the foundation of the entire permissions system: when the kernel decides whether you’re allowed to read a file, run a program, or kill a process, it’s comparing user and group identities, not names typed on a keyboard. Understanding how Linux represents users and groups internally is the key to understanding permissions, sudo, ownership, and multi-user security as a whole.
Overview / How it works
Linux was designed from the start as a multi-user operating system, inherited from Unix. Multiple people (or service accounts) can be logged in and running processes on the same machine at once, and the kernel keeps them separated using numeric identifiers. A username like alice is just a human-friendly label; internally, the kernel only cares about a number called the UID (user ID). Every process, every file, and every directory on disk is tagged with a UID that says who owns it. Groups work the same way with a GID (group ID) — a numeric identifier that the kernel uses to decide group-level access.
The mapping between human-readable names and these numbers lives in plain text files:
/etc/passwd— one line per user account, mapping username to UID, primary GID, home directory, and login shell./etc/shadow— the actual hashed passwords and password-aging rules, kept separate from/etc/passwdand readable only by root, so that any program that needs to read usernames (likels -lresolving an owner) doesn’t also get password hashes./etc/group— one line per group, mapping group name to GID and a list of supplementary members./etc/gshadow— group passwords and group administrators (rarely used today, but present for completeness).
Every user has exactly one primary group (recorded by GID in /etc/passwd) and can additionally belong to any number of supplementary groups (recorded by membership lists in /etc/group). When you create a new file, it’s normally owned by your UID and your primary GID. When the kernel checks whether you can access someone else’s file via group permissions, it checks whether your primary GID or any of your supplementary GIDs matches the file’s group.
UID 0 is special
UID 0 is always the root user — the superuser that bypasses nearly all permission checks. There is only ever one UID 0, but there can be multiple usernames mapped to it (a bad, confusing practice best avoided). Modern distributions strongly discourage logging in as root directly; instead, an ordinary user is granted membership in a privileged group (sudo on Debian/Ubuntu, wheel on RHEL/Fedora) and uses sudo to run individual commands as root, which also leaves an audit trail of who ran what.
UID ranges: humans vs. system accounts
Not every entry in /etc/passwd is a real person. Services like the web server or the print spooler need their own identity too, so that files they own aren’t accessible to arbitrary users. Debian/Ubuntu reserves low UIDs for these system/service accounts and starts regular human accounts at 1000; RHEL/Fedora traditionally starts human accounts at 1000 as well (older systems used 500). System accounts typically have a login shell of /usr/sbin/nologin or /bin/false, meaning nobody can actually log in interactively as that account — it exists purely so processes can own files and run with limited privilege.
| Range (typical Debian/Ubuntu) | Meaning |
|---|---|
| 0 | root, the superuser |
| 1–999 | System and service accounts (e.g. www-data, syslog) |
| 1000+ | Regular human user accounts |
Syntax
These concepts are usually inspected, not edited, with a small set of read-only commands:
| Command | Purpose |
|---|---|
whoami |
Print the current effective username |
id [username] |
Print UID, primary GID, and all group memberships for the current user or a named user |
groups [username] |
List the group names a user belongs to |
getent passwd <username> |
Look up a single account’s /etc/passwd entry (works with remote/LDAP accounts too, not just local files) |
getent group <groupname> |
Look up a single group’s /etc/group entry |
The account-management commands (useradd, usermod, groupadd, gpasswd) that actually create and modify these entries are covered in their own lesson later in this section — here we’re focused on understanding the data model itself.
The general shape of the two core account files looks like this:
username:x:UID:GID:GECOS:home_directory:login_shell
groupname:x:GID:member1,member2,member3
Examples
Example 1: check who you are and what groups the kernel considers you a member of.
whoami
id
Output:
alice
uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),999(docker)
whoami just prints the name attached to your effective UID. id is far more useful: it shows the numeric UID and primary GID, the resolved names in parentheses, and every supplementary group — here, alice is UID 1000, her primary group is also called alice with GID 1000 (Debian/Ubuntu creates a private group per user by default), and she additionally belongs to sudo and docker.
Example 2: look up the raw account record for a specific user.
grep alice /etc/passwd
Output:
alice:x:1000:1000:Alice Smith,,,:/home/alice:/bin/bash
Reading the fields left to right: username alice, a placeholder x (the real password hash lives in /etc/shadow, not here), UID 1000, primary GID 1000, the GECOS field holding her full name, home directory /home/alice, and login shell /bin/bash. This file is world-readable by design — many programs need to resolve UIDs to names — which is exactly why passwords were moved out to the root-only /etc/shadow decades ago.
Example 3: inspect a group and a system service account.
grep sudo /etc/group
getent passwd www-data
Output:
sudo:x:27:alice,bob
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
The sudo group has GID 27 and two supplementary members, alice and bob — anyone in this list can run sudo (assuming the sudoers policy allows it). The www-data line shows a typical system account: UID and GID 33, no real home directory usage, and a shell of /usr/sbin/nologin so nobody can use it to open an interactive session — it exists only so the web server process has its own restricted identity to own files under.
How it works step by step
Here’s what actually happens when you log in and then run a command:
- The login program (or SSH daemon) looks up the username you typed in
/etc/passwdto find the UID, primary GID, home directory, and shell. - It checks the password you entered against the hash stored in
/etc/shadowfor that username. - On success, it calls kernel functions to set the new process’s real and effective UID/GID to your account’s values, then reads
/etc/groupto build the full supplementary group list for your account. - It launches your login shell (e.g.
/bin/bash) as that user; every process you start afterward (a text editor,ls, a script) inherits the same UID and group list, because child processes inherit credentials from their parent. - From then on, whenever any process tries to open a file, the kernel compares that process’s effective UID against the file’s owner UID, and the process’s GID list against the file’s group GID, to decide which of the three permission sets (owner/group/other) applies.
This is why groups are so powerful for access control: instead of listing every individual user who should have access to a shared resource, you add users to a group once, and every file owned by that group automatically respects the membership — no per-file editing required.
Common Mistakes
Mistake 1: editing /etc/passwd or /etc/group directly with a text editor. A stray typo — a missing colon, an extra newline — can corrupt the file and lock every user, including root, out of the system.
sudo nano /etc/passwd
Use the dedicated tools instead, which validate syntax and lock the file against simultaneous edits: vipw for /etc/passwd, vigr for /etc/group, or better yet the account-management commands (useradd, usermod, groupadd) covered in the next lessons, which update these files safely for you.
sudo usermod -aG docker alice
Mistake 2: using usermod -G instead of usermod -aG when adding a group. The -G flag replaces the entire supplementary group list, not appends to it — a very common way to accidentally strip a user’s existing group memberships.
sudo usermod -G docker alice
If alice was already in sudo, this silently removes her from sudo and leaves her only in docker. Always include -a (append) unless you genuinely intend to overwrite the whole list:
sudo usermod -aG docker alice
Mistake 3: expecting a new group membership to apply immediately. Group membership is read once, when a login session starts. Adding a user to a group doesn’t change the groups already attached to their currently running shell.
groups alice
Output (still shows the old list right after being added to docker):
alice : alice sudo
The fix is to either fully log out and back in, or, in the same terminal, start a new shell with the updated group applied via newgrp:
newgrp docker
Best Practices
- Never log in or work as root directly — grant trusted accounts membership in
sudo(Debian/Ubuntu) orwheel(RHEL/Fedora) and usesudoper command instead. - Prefer
usermod -aG(append) overusermod -G(replace) whenever adding someone to an additional group. - Use groups to model roles (
developers,docker,backup-operators) rather than granting permissions to individual users one by one — it scales better and is easier to audit. - Leave the reserved system UID/GID range (below 1000 on Debian/Ubuntu) for service accounts; don’t hand-assign a human user a UID in that range.
- Give service accounts a non-interactive shell like
/usr/sbin/nologinso they can own files and run daemons without being usable for interactive login. - Use
vipw/vigr, or higher-level tools likeuseradd/groupadd, instead of hand-editing/etc/passwd,/etc/shadow, or/etc/group. - Periodically audit
/etc/passwdand/etc/groupfor stale accounts or unexpected members of privileged groups likesudo.
Practice Exercises
Exercise 1. Run whoami and then id on your own system. Identify your UID, your primary group’s GID, and list every supplementary group you belong to. Are you a member of sudo or wheel?
Exercise 2. Use getent passwd www-data (or another service account present on your system, such as syslog) and note its UID, home directory, and shell. Explain in your own words why that account’s shell is set to something like /usr/sbin/nologin instead of /bin/bash.
Exercise 3. A teammate says they were just added to the docker group with sudo usermod -aG docker bob, but running a docker command in their existing terminal still gives a permission error. Explain why, and describe the two ways they could fix it without rebooting the machine.
Summary
- The kernel identifies users and groups by numeric UID and GID, not by name — usernames are just a human-friendly lookup.
/etc/passwdmaps usernames to UID, primary GID, home directory, and shell;/etc/shadowholds password hashes separately and is root-only;/etc/groupmaps group names to GID and supplementary members.- Every user has exactly one primary group but can belong to many supplementary groups, and the kernel checks all of them during permission checks.
- UID 0 is always root; low UIDs are reserved for system/service accounts, and human accounts typically start at 1000.
- Use
sudoinstead of logging in as root, useusermod -aGto append (not replace) group membership, and remember new group membership requires a fresh login session ornewgrpto take effect.
