LFCA 21 🐧 What Users and Groups Are
Every file on a Linux system has an owner and a group. Every process runs as some user. Every login, every sudo, every permission check comes down to a single question: who are you, and what are you allowed to do? The answer is built from two concepts that sit underneath everything else — users and groups. A user is an identity: a name, a numeric ID, a home directory, a shell. A group is a collection of users that can be granted permissions together, so that administration does not require repeating the same grant for every individual. This chapter covers what users and groups actually are, where they are stored, how the kernel identifies them, and why the split between user and group exists at all. It does not cover creating or managing them — that is the next chapter. Here the goal is the mental model: the identity model that every permission check, every ls -l output, and every chown command depends on.
Key point: Every user has a UID (user ID), a number the kernel uses internally. Every group has a GID (group ID). Names are a human convenience — the kernel only knows numbers. Users are stored in /etc/passwd, groups in /etc/group, and passwords (or their hashes) in /etc/shadow. A user has exactly one primary group and can belong to any number of supplementary groups. The id command shows the current user’s UID, primary GID, and supplementary groups.
Why the system needs identities
A Linux system is multi-user by design. It was built from the beginning to support many people logged in at once, each with their own files, their own processes, and their own permissions. The identity model is what makes that possible without chaos.
The kernel’s view. The kernel does not know user names. It knows numbers — UIDs and GIDs. When a process runs, it carries a UID and a GID. When it tries to read a file, the kernel compares the process’s UID and GIDs against the file’s owner and group and the file’s permission bits. The result is allow or deny. No names are involved.
The userspace view. Humans use names. alice, bob, www-data, root. The translation between names and numbers happens in userspace, through files in /etc that the kernel reads at login and that tools like ls and chown consult. When you type ls -l and see alice alice, that is userspace translating the UID 1000 and GID 1000 into names for your benefit. The kernel saw only the numbers.
Why the split exists. Separating identity (UID) from presentation (name) has real benefits. Renaming a user does not change file ownership, because the files store UIDs, not names. Moving a filesystem between systems keeps ownership intact as long as the UIDs mean the same thing. And the kernel’s permission checks stay simple: compare integers.
Why names can go stale. If a UID appears on a file but no user with that UID exists in /etc/passwd, ls -l shows the raw number instead of a name. This happens when a user is deleted but their files remain, or when a filesystem from another system is mounted with UIDs that do not exist locally. It is not an error — it is the identity model working as designed.
Why
rootis special. UID0isroot, the superuser. The kernel treats UID0as exempt from most permission checks. This is not a group membership or a special flag — it is a hardcoded rule. That is whysudoexists: instead of logging in as root, a normal user temporarily runs a command with UID0, and the kernel grants it the privileges that come with that number.
The user: name, UID, home, shell
A user is defined by an entry in /etc/passwd. Each line has seven colon-separated fields, and each field carries a piece of the identity.
alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
Reading left to right: the username is alice. The password placeholder is x, meaning the real password hash is in /etc/shadow. The UID is 1000. The primary GID is 1000. The comment field (also called GECOS) is Alice Smith. The home directory is /home/alice. The login shell is /bin/bash.
Why /etc/passwd is world-readable. The file has to be readable by every process that needs to translate a UID to a name — ls, ps, top, and many others. Since it is readable by all, it cannot contain password hashes. Those live in /etc/shadow, which is readable only by root. The x in the password field is a pointer: “the real secret is elsewhere.”
The system users. Not every entry in /etc/passwd is a human. The file contains dozens of system accounts — daemon, bin, sys, www-data, sshd, nobody — each with a UID below 1000 on most distributions. These accounts exist to own files and run services with limited privileges. www-data owns the web server’s files so the web server does not need to run as root. sshd runs the SSH daemon. They are identities for processes, not for people.
Why the UID ranges matter. Conventionally, UIDs 0 through 999 are reserved for system accounts, and 1000 and above are for regular users. The useradd tool follows this convention by default. The boundary is not enforced by the kernel, but tools and administrators respect it, and it keeps the system accounts distinct from the human ones.
Why the login shell can be /usr/sbin/nologin. System accounts often have nologin or /bin/false as their shell. This is a deliberate barrier: the account exists for file ownership and process identity, but no one can log in as it. The login program checks the shell and refuses to start a session if it is nologin. It is one of the simplest security measures on the system.
The group: name, GID, members
A group is defined by an entry in /etc/group. Each line has four colon-separated fields.
developers:x:1001:alice,bob,carol
The group name is developers. The password placeholder is x. The GID is 1001. The member list is alice,bob,carol.
Why groups exist. Without groups, granting access to a shared resource would require granting it to each user individually. A project directory that three developers need to write to would have to be owned by one of them and chmod’d to allow others, or each would need their own permission entry. Groups solve this: make the directory owned by group developers, give the group write permission, and add the three users to the group. One grant, three beneficiaries.
Why the member list does not tell the whole story. A user’s primary group is recorded in /etc/passwd, not in /etc/group. So alice might have primary group alice (GID 1000) and also be a member of developers, sudo, and docker. The /etc/group file lists her in developers, sudo, and docker, but her primary group appears in /etc/passwd. Both places have to be consulted to know a user’s full group membership.
Why a user has exactly one primary group. When a user creates a file, the file’s group is the user’s primary group by default. This is the group that appears in ls -l output as the second name. Supplementary groups grant additional access but do not affect new file ownership unless the directory has the setgid bit set.
Why supplementary groups matter for permissions. Permission checks consider all of a user’s groups, not just the primary one. If a file is owned by group developers with group write permission, and alice is a supplementary member of developers, she can write to the file. The primary group being different does not matter. The kernel checks the full group list.
Why the group model is coarse. Linux groups are flat — a group is a list of users, and there is no nesting. If an organization has teams that overlap, the groups have to be maintained by hand. This is a known limitation, and it is one reason larger environments use directory services like LDAP or Active Directory rather than plain
/etc/group. For a single system with a handful of users, the flat model is enough.
How the kernel identifies users and groups
The kernel knows only numbers. When a user logs in, the login program looks up the username in /etc/passwd, finds the UID, and starts a shell process with that UID. From that point on, every process the user launches inherits the UID. Every file operation checks the process’s UID and GIDs against the file’s ownership.
The real UID and the effective UID. A process has both a real UID (who started it) and an effective UID (what permissions it runs with). Normally they are the same. When a program has the setuid bit set, the effective UID changes to the file’s owner while the real UID stays as the invoking user. This is how passwd works — a normal user can run it, and it temporarily runs as root to write to /etc/shadow.
The supplementary groups. A process also carries a list of supplementary GIDs, inherited from the login session. Permission checks compare the file’s group against the process’s primary GID and every supplementary GID. A match on any of them grants group access.
Why the kernel does not consult /etc/passwd for every check. Reading a file for every permission check would be slow. Instead, the login process looks up the identity once, and the kernel caches the UID and GIDs in the process structure. Permission checks are pure integer comparisons against the cached values. This is why changing a user’s group membership does not take effect for existing sessions — the cached groups are stale until the user logs out and back in.
Why this matters for administration. When you add a user to a group with usermod -aG, the change is written to /etc/group immediately, but the user’s current shell session still has the old group list. The new group takes effect on the next login. This is a common source of confusion: the permission is granted, but the session does not see it.
Viewing identity with id and related tools
The id command prints the current user’s identity: UID, primary GID, and all supplementary groups.
$ id
uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),1001(developers)
The output shows the username in parentheses next to each number, which makes it readable. The groups list includes the primary group first, then the supplementary groups.
Querying another user. id bob prints bob‘s identity instead of the current user’s.
$ id bob
uid=1001(bob) gid=1001(bob) groups=1001(bob),1001(developers)
The groups command. groups prints just the group names, without the numbers.
$ groups
alice sudo developers
The whoami command. Prints the current username.
$ whoami
alice
Why these tools are the starting point for permission debugging. When a user cannot access a file, the first question is “what groups are they in?” The id command answers it. If the file is group-owned by developers and the user’s id output does not list developers, the problem is group membership. If it does list developers, the problem is the file’s permission bits. The id output narrows the diagnosis in one step.
Why the name in parentheses matters. If id prints a number without a name — uid=1000 instead of uid=1000(alice) — the UID does not exist in /etc/passwd. This is a stale identity: the user was deleted, or the filesystem has UIDs from another system. The number is still valid to the kernel, but no name maps to it.
Why
idis worth running beforesudo. A surprising number of permission problems come from running commands as the wrong user. A file that is not writable byalicemay be writable byroot, and vice versa. Runningidbefore and aftersudo -ishows the difference, and it makes the permission model concrete: the same shell, the same files, different UID, different results.
The files that define identity
Three files hold the identity model: /etc/passwd, /etc/group, and /etc/shadow. Each has a different purpose and a different access level.
/etc/passwd — user accounts. World-readable. Seven fields per line. The password field contains x when the hash is in /etc/shadow.
/etc/group — group definitions. World-readable. Four fields per line. The member list is a comma-separated list of usernames.
/etc/shadow — password hashes and aging information. Readable only by root. Nine fields per line, including the hash, the last change date, and expiration policy.
Why /etc/shadow exists. Originally, password hashes were in /etc/passwd. But /etc/passwd has to be world-readable, and a readable hash is a target for offline cracking. Moving the hashes to /etc/shadow and restricting its permissions removed that exposure. The x in /etc/passwd is the marker that the real hash is elsewhere.
Why the split matters for backups. /etc/passwd and /etc/group are safe to back up and share. /etc/shadow contains secrets and should be protected. A backup that includes /etc/shadow has to be treated with the same care as the passwords themselves.
Why editing these files by hand is risky. Tools like useradd, usermod, groupadd, and passwd update all three files consistently and validate input. Editing /etc/passwd directly can leave the files out of sync, and a malformed line can lock out all logins. The tools exist because the files are interdependent.
Complete Example Session
# ============================================
# PART 1: CURRENT IDENTITY
# ============================================
id
# uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),1001(developers)
whoami
# alice
groups
# alice sudo developers
# ============================================
# PART 2: ANOTHER USER'S IDENTITY
# ============================================
id bob
# uid=1001(bob) gid=1001(bob) groups=1001(bob),1001(developers)
id root
# uid=0(root) gid=0(root) groups=0(root)
# ============================================
# PART 3: READING /etc/passwd
# ============================================
head -3 /etc/passwd
# root:x:0:0:root:/root:/bin/bash
# daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
# bin:x:2:2:bin:/bin:/usr/sbin/nologin
grep alice /etc/passwd
# alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash
# ============================================
# PART 4: READING /etc/group
# ============================================
grep developers /etc/group
# developers:x:1001:alice,bob,carol
grep sudo /etc/group
# sudo:x:27:alice
# ============================================
# PART 5: SYSTEM ACCOUNTS
# ============================================
# System accounts have low UIDs and nologin shells
awk -F: '$3 < 1000 { print $1, $3, $7 }' /etc/passwd | head -5
# root 0 /bin/bash
# daemon 1 /usr/sbin/nologin
# bin 2 /usr/sbin/nologin
# sys 3 /usr/sbin/nologin
# sync 4 /bin/sync
# ============================================
# PART 6: UID RANGES
# ============================================
# Regular users start at 1000
awk -F: '$3 >= 1000 && $3 < 65534 { print $1, $3 }' /etc/passwd
# alice 1000
# bob 1001
# ============================================
# PART 7: PRIMARY VS SUPPLEMENTARY GROUPS
# ============================================
# Primary group is in /etc/passwd
grep alice /etc/passwd | awk -F: '{ print "Primary GID:", $4 }'
# Primary GID: 1000
# Supplementary groups are in /etc/group
grep -E "alice" /etc/group
# sudo:x:27:alice
# developers:x:1001:alice,bob,carol
# ============================================
# PART 8: THE SHADOW FILE
# ============================================
sudo head -1 /etc/shadow
# root:$6$...:19000:0:99999:7:::
# The hash is visible only to root
# Regular users get permission denied
cat /etc/shadow
# cat: /etc/shadow: Permission denied
# ============================================
# PART 9: TRANSLATING UID TO NAME
# ============================================
# File ownership stores UIDs, not names
touch /tmp/testfile
ls -ln /tmp/testfile
# -rw-r--r-- 1 1000 1000 0 Mar 15 10:00 /tmp/testfile
ls -l /tmp/testfile
# -rw-r--r-- 1 alice alice 0 Mar 15 10:00 /tmp/testfile
# -n shows numbers; without it, names are looked up
# ============================================
# PART 10: STALE UIDs
# ============================================
# A file owned by a UID with no name
ls -ln /tmp/orphan 2>/dev/null
# -rw-r--r-- 1 4321 4321 0 Mar 15 10:00 /tmp/orphan
ls -l /tmp/orphan 2>/dev/null
# -rw-r--r-- 1 4321 4321 0 Mar 15 10:00 /tmp/orphan
# No name — UID 4321 does not exist in /etc/passwd
Each part isolates one concept. Parts 1 and 2 show the identity of users. Parts 3 through 6 show the files and their structure. Parts 7 through 9 show the primary/supplementary split and the UID-to-name translation. Part 10 shows what a stale UID looks like.
Quick Reference
The Identity Files
| File | Purpose | Permissions |
|---|---|---|
/etc/passwd | User accounts | World-readable |
/etc/group | Group definitions | World-readable |
/etc/shadow | Password hashes | Root only |
/etc/passwd Fields
| # | Field | Example |
|---|---|---|
| 1 | Username | alice |
| 2 | Password placeholder | x |
| 3 | UID | 1000 |
| 4 | Primary GID | 1000 |
| 5 | Comment (GECOS) | Alice Smith |
| 6 | Home directory | /home/alice |
| 7 | Login shell | /bin/bash |
/etc/group Fields
| # | Field | Example |
|---|---|---|
| 1 | Group name | developers |
| 2 | Password placeholder | x |
| 3 | GID | 1001 |
| 4 | Member list | alice,bob,carol |
UID Ranges
| Range | Purpose |
|---|---|
0 | root |
1–999 | System accounts |
1000+ | Regular users |
65534 | nobody (unprivileged) |
Identity Commands
| Command | Output |
|---|---|
id | UID, GID, all groups |
id user | Another user’s identity |
whoami | Current username |
groups | Group names only |
ls -ln | File ownership as numbers |
ls -l | File ownership as names |
Primary vs Supplementary
| Aspect | Primary Group | Supplementary |
|---|---|---|
| Recorded in | /etc/passwd | /etc/group |
| How many | Exactly one | Zero or more |
| New file ownership | Yes | No (unless setgid) |
| Permission checks | Yes | Yes |
| Takes effect | At login | At login |
Best Practices
✅ Do This:
# Check identity before debugging permissions
id # ✅
# Use id to check another user's groups
id bob # ✅
# Read /etc/passwd for user structure
grep alice /etc/passwd # ✅
# Use ls -ln when names are ambiguous
ls -ln /path/to/file # ✅
# Recognize system accounts by low UIDs
awk -F: '$3 < 1000' /etc/passwd # ✅
# Protect /etc/shadow
sudo chmod 640 /etc/shadow # ✅
❌ Don’t Do This:
# Don't edit /etc/passwd directly
vim /etc/passwd # use useradd/usermod # ⚠️
# Don't assume group changes take effect immediately
# Existing sessions keep old groups until re-login # ⚠️
# Don't expect names when UIDs are stale
# ls shows the number if no user matches # ⚠️
# Don't read /etc/shadow without sudo
cat /etc/shadow # Permission denied # ⚠️
# Don't assume a user's only group is their primary
# Supplementary groups matter for permissions too # ⚠️
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
| Group added but access denied | Session groups stale | Log out and back in |
| File shows number not name | Stale UID | Check /etc/passwd |
| System account has a shell | Security risk | Set nologin |
| Primary group confused with only group | Supplementary missed | Use id |
/etc/shadow unreadable | Expected | Use sudo |
| Editing identity files by hand | Inconsistency | Use useradd, usermod |
| UID collision across systems | Wrong ownership | Coordinate UIDs |
Real-World Examples
1. Check current identity
id
2. Check another user
id www-data
3. List all groups
groups
4. Find a user’s entry
grep alice /etc/passwd
5. Find a group’s members
grep developers /etc/group
6. List system accounts
awk -F: '$3 < 1000 { print $1 }' /etc/passwd
7. Show ownership as numbers
ls -ln /var/log
8. Check a service account’s shell
getent passwd www-data
9. Verify shadow permissions
sudo ls -l /etc/shadow
10. Look up a UID
getent passwd 1000
Visual: The Identity Model
┌──────────────────────────────────────────────────────────┐
│ USERSPACE │
│ │
│ "alice" ──► /etc/passwd ──► UID 1000, GID 1000 │
│ "developers" ──► /etc/group ──► GID 1001 │
│ │
│ Names are human-readable. │
│ Files translate names to numbers. │
│ │
├──────────────────────────────────────────────────────────┤
│ KERNEL │
│ │
│ Process carries: │
│ real UID = 1000 │
│ effective UID = 1000 │
│ GIDs = [1000, 27, 1001] │
│ │
│ File carries: │
│ owner UID = 1000 │
│ group GID = 1001 │
│ mode bits = rwxrwx--- │
│ │
│ Permission check: integer comparison. │
│ │
└──────────────────────────────────────────────────────────┘
Visual: The Three Files
┌──────────────────────────────────────────────────────────┐
│ /etc/passwd (world-readable) │
│ │
│ alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ └── shell │
│ │ │ │ │ └── home │
│ │ │ │ └── comment │
│ │ │ └── primary GID │
│ │ └── UID │
│ └── password placeholder (hash is in /etc/shadow) │
│ │
├──────────────────────────────────────────────────────────┤
│ /etc/group (world-readable) │
│ │
│ developers:x:1001:alice,bob,carol │
│ │ │ │ │ │
│ │ │ │ └── members │
│ │ │ └── GID │
│ │ └── password placeholder │
│ └── group name │
│ │
├──────────────────────────────────────────────────────────┤
│ /etc/shadow (root only) │
│ │
│ alice:$6$xyz...:19000:0:99999:7::: │
│ │ │ │ │ │ │
│ │ │ │ │ └── warning days │
│ │ │ │ └── max days │
│ │ │ └── min days │
│ │ └── last change │
│ └── password hash │
│ │
└──────────────────────────────────────────────────────────┘
Visual: Primary vs Supplementary Groups
┌──────────────────────────────────────────────────────────┐
│ alice │
│ │
│ Primary group (from /etc/passwd): │
│ alice (GID 1000) │
│ └── new files she creates are owned by this group │
│ │
│ Supplementary groups (from /etc/group): │
│ sudo (GID 27) │
│ developers (GID 1001) │
│ └── grant additional access, no effect on new files │
│ unless the directory has setgid │
│ │
│ Permission checks consider ALL groups. │
│ │
└──────────────────────────────────────────────────────────┘
Visual: UID Translation
┌──────────────────────────────────────────────────────────┐
│ File on disk stores: │
│ owner UID = 1000 │
│ group GID = 1001 │
│ │
│ ls -ln shows: │
│ -rw-r--r-- 1 1000 1001 ... │
│ │
│ ls -l looks up 1000 and 1001 in /etc/passwd and │
│ /etc/group: │
│ -rw-r--r-- 1 alice developers ... │
│ │
│ If the UID has no entry: │
│ -rw-r--r-- 1 4321 4321 ... │
│ (stale UID — no name) │
│ │
└──────────────────────────────────────────────────────────┘
Visual: Where the Kernel Gets Its Answer
┌──────────────────────────────────────────────────────────┐
│ Login │
│ │ │
│ ▼ │
│ Look up username in /etc/passwd │
│ │ │
│ ▼ │
│ Get UID, primary GID │
│ │ │
│ ▼ │
│ Look up supplementary groups in /etc/group │
│ │ │
│ ▼ │
│ Start shell process with: │
│ real UID, effective UID, GID list │
│ │ │
│ ▼ │
│ Kernel caches these in the process struct │
│ │ │
│ ▼ │
│ Every file operation compares against the cache │
│ (no /etc lookup per check) │
│ │
└──────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| User identity | UID (number) |
| Group identity | GID (number) |
| User database | /etc/passwd |
| Group database | /etc/group |
| Password hashes | /etc/shadow |
| root UID | 0 |
| System UID range | 1–999 |
| Regular user range | 1000+ |
| Primary group | One per user |
| Supplementary groups | Zero or more |
| Kernel view | UIDs and GIDs only |
Key takeaways:
- Every user has a UID and every group has a GID — names are a userspace convenience, and the kernel works with numbers only
/etc/passwdholds user accounts,/etc/groupholds groups, and/etc/shadowholds password hashes — the first two are world-readable, the third is root-only- A user has exactly one primary group and any number of supplementary groups — the primary group is recorded in
/etc/passwd, the supplementary groups in/etc/group - Permission checks consider all of a user’s groups, not just the primary one
- System accounts have UIDs below 1000 and usually a
nologinshell — they exist to own files and run services, not for interactive login - The
idcommand is the starting point for permission debugging — it shows UID, primary GID, and all supplementary groups - Changing group membership does not affect existing sessions — the process’s cached group list is stale until the user logs out and back in
- Files store UIDs, not names — when a UID has no entry in
/etc/passwd,ls -lshows the raw number - The identity model is what makes multi-user Linux possible — every permission check, every
sudo, every file access runs through it
Remember: Users and groups are the foundation of Linux permissions. A user is an identity with a numeric UID; a group is a collection with a numeric GID. The files in /etc define them, the kernel caches them, and every permission check compares them. Understanding this model is what makes the rest of the permission system — chmod, chown, sudo, file modes — make sense. The next chapter covers how to create and manage these identities with useradd, usermod, groupadd, and their companions.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!