| | |

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 root is special. UID 0 is root, the superuser. The kernel treats UID 0 as exempt from most permission checks. This is not a group membership or a special flag — it is a hardcoded rule. That is why sudo exists: instead of logging in as root, a normal user temporarily runs a command with UID 0, 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 id is worth running before sudo. A surprising number of permission problems come from running commands as the wrong user. A file that is not writable by alice may be writable by root, and vice versa. Running id before and after sudo -i shows 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

FilePurposePermissions
/etc/passwdUser accountsWorld-readable
/etc/groupGroup definitionsWorld-readable
/etc/shadowPassword hashesRoot only

/etc/passwd Fields

#FieldExample
1Usernamealice
2Password placeholderx
3UID1000
4Primary GID1000
5Comment (GECOS)Alice Smith
6Home directory/home/alice
7Login shell/bin/bash

/etc/group Fields

#FieldExample
1Group namedevelopers
2Password placeholderx
3GID1001
4Member listalice,bob,carol

UID Ranges

RangePurpose
0root
1–999System accounts
1000+Regular users
65534nobody (unprivileged)

Identity Commands

CommandOutput
idUID, GID, all groups
id userAnother user’s identity
whoamiCurrent username
groupsGroup names only
ls -lnFile ownership as numbers
ls -lFile ownership as names

Primary vs Supplementary

AspectPrimary GroupSupplementary
Recorded in/etc/passwd/etc/group
How manyExactly oneZero or more
New file ownershipYesNo (unless setgid)
Permission checksYesYes
Takes effectAt loginAt 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

PitfallProblemSolution
Group added but access deniedSession groups staleLog out and back in
File shows number not nameStale UIDCheck /etc/passwd
System account has a shellSecurity riskSet nologin
Primary group confused with only groupSupplementary missedUse id
/etc/shadow unreadableExpectedUse sudo
Editing identity files by handInconsistencyUse useradd, usermod
UID collision across systemsWrong ownershipCoordinate 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

ItemValue
User identityUID (number)
Group identityGID (number)
User database/etc/passwd
Group database/etc/group
Password hashes/etc/shadow
root UID0
System UID range1–999
Regular user range1000+
Primary groupOne per user
Supplementary groupsZero or more
Kernel viewUIDs 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/passwd holds user accounts, /etc/group holds groups, and /etc/shadow holds 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 nologin shell — they exist to own files and run services, not for interactive login
  • The id command 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 -l shows 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!