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/passwd and readable only by root, so that any program that needs to read usernames (like ls -l resolving 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:

  1. The login program (or SSH daemon) looks up the username you typed in /etc/passwd to find the UID, primary GID, home directory, and shell.
  2. It checks the password you entered against the hash stored in /etc/shadow for that username.
  3. 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/group to build the full supplementary group list for your account.
  4. 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.
  5. 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) or wheel (RHEL/Fedora) and use sudo per command instead.
  • Prefer usermod -aG (append) over usermod -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/nologin so they can own files and run daemons without being usable for interactive login.
  • Use vipw/vigr, or higher-level tools like useradd/groupadd, instead of hand-editing /etc/passwd, /etc/shadow, or /etc/group.
  • Periodically audit /etc/passwd and /etc/group for stale accounts or unexpected members of privileged groups like sudo.

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/passwd maps usernames to UID, primary GID, home directory, and shell; /etc/shadow holds password hashes separately and is root-only; /etc/group maps 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 sudo instead of logging in as root, use usermod -aG to append (not replace) group membership, and remember new group membership requires a fresh login session or newgrp to take effect.