Home / Learn Linux / Lesson 13
Users and groups
Where accounts live, adding and changing users and groups, and who is logged in.
- Lesson
- 13 of 30
- Time
- About 40 minutes
On this page
- Users are numbers
- /etc/passwd: the list of users
- /etc/shadow: the passwords
- Groups
- Creating users
- Changing users: usermod
- Managing groups
- Deleting users
- Who's logged in?
- Common mistakes
- Practice
- Cheat sheet
Users are numbers
Linux doesn't really care about user names. Every user is a number, the UID (user ID), and every group is a GID. The names are a lookup table for humans. id shows yours:
$ id uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),102(lxd) $ id root uid=0(root) gid=0(root) groups=0(root)
Root is always UID 0, and that number is what makes root all-powerful, not the name. Ubuntu gives the first human user 1000 and counts up from there. The numbers below 1000 belong to system users: accounts that exist only so a service can run with its own limited rights, like www-data for web servers or syslog for logging. Nobody logs in as them.
/etc/passwd: the list of users
Every user has one line in /etc/passwd, with seven fields separated by colons:
$ grep -E "^(root|syslog|ubuntu):" /etc/passwd
root:x:0:0:root:/root:/bin/bash
syslog:x:100:101::/nonexistent:/usr/sbin/nologin
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash| Field | ubuntu's value | Means |
|---|---|---|
| 1 | ubuntu | User name |
| 2 | x | The password is kept in /etc/shadow instead |
| 3 | 1000 | UID |
| 4 | 1000 | Primary group's GID |
| 5 | Ubuntu | Full name or comment |
| 6 | /home/ubuntu | Home directory |
| 7 | /bin/bash | Login shell |
System users usually have /usr/sbin/nologin as their shell, which refuses logins politely. Anyone can read /etc/passwd, because programs need it to turn UIDs into names (that's how ls -l shows ubuntu instead of 1000).
getent passwd name looks a user up the same way programs do. On a plain server that's the same as reading the file. On a company network, users might come from a central directory instead, and getent finds them there too:
$ getent passwd ubuntu
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash/etc/shadow: the passwords
The password hashes live in /etc/shadow, which only root can read:
$ sudo grep -E "^(root|ubuntu):" /etc/shadow
root:*:20654:0:99999:7:::
ubuntu:!:20747:0:99999:7:::The second field is the password hash. ! or * means there's no usable password, so nobody can log in with one. That's how Multipass sets up ubuntu (it uses an SSH key instead) and how Ubuntu locks root. The third field is the day the password was last changed, counted in days since 1 January 1970, and the rest control expiry (more on that below).
A real hash looks like $y$j9T$.... The $y$ says it's yescrypt, the slow-on-purpose algorithm Ubuntu uses, so that someone who steals the file can't try billions of guesses per second.
Try it
- What's the UID of the
www-datauser, and what's its shell? - How many users does the system have in total?
Answer
$ grep ^www-data: /etc/passwd www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin $ wc -l < /etc/passwd 34
UID 33, and nologin as its shell, because it's a system user for web servers.
Groups
A group is a named set of users, used to share access: everyone in devs can write to the project directory, everyone in sudo can use sudo. Each user has one primary group (field 4 in /etc/passwd, used for new files they create) and any number of supplementary groups. Ubuntu makes a private primary group with the same name for every user.
Groups are listed in /etc/group, with their members in the last field:
$ grep -E "^(sudo|adm|ubuntu):" /etc/group adm:x:4:syslog,ubuntu,ravi sudo:x:27:ubuntu,asha ubuntu:x:1000: $ groups ubuntu adm cdrom sudo dip lxd
Creating users
There are two tools, and the difference matters:
adduseris Ubuntu's friendly tool. It creates the home directory, copies the starter files from/etc/skel, asks for a password and fills in sensible defaults.useraddis the low-level one. It does only what you tell it. Without-mit doesn't create a home directory, and without-sthe shell is/bin/shinstead of Bash.
On Ubuntu, use adduser when you're typing, and useradd with all its options in scripts, where you want exact control. Here's adduser without a password prompt (--disabled-password means no password yet):
$ sudo adduser --disabled-password --comment "Asha Rao" ashaAnd the same kind of user with useradd, spelling out every default you want:
$ sudo useradd -m -s /bin/bash -c "Ravi Kumar" ravi $ grep -E "^(asha|ravi):" /etc/passwd asha:x:1001:1001:Asha Rao:/home/asha:/bin/bash ravi:x:1002:1002:Ravi Kumar:/home/ravi:/bin/bash $ ls -la /home total 20 drwxr-xr-x 5 root root 4096 Oct 21 12:15 . drwxr-xr-x 19 root root 4096 Oct 21 11:06 .. drwxr-x--- 2 asha asha 4096 Oct 21 12:15 asha drwxr-x--- 2 ravi ravi 4096 Oct 21 12:15 ravi drwxr-x--- 14 ubuntu ubuntu 4096 Oct 21 12:15 ubuntu
Both got a home directory with /etc/skel's files in it, and both have Bash because we asked for it. Home directories are drwxr-x---: the owner can do anything, the user's group can look, and everyone else is kept out.
Setting passwords
passwd name sets a password interactively. It asks twice and shows nothing while you type:
$ sudo passwd ravi
New password:
Retype new password:
passwd: password updated successfullyIn scripts, chpasswd reads name:password lines instead:
$ echo "ravi:Change.Me.42" | sudo chpasswd $ sudo passwd -S ravi ravi P 2026-10-21 0 99999 7 -1
P means a usable password is set (L would be locked, NP no password). Now you can become Ravi with su, which asks for Ravi's password:
ubuntu@linux:~$ su - ravi Password: ravi@linux:~$ whoami ravi ravi@linux:~$ pwd /home/ravi ravi@linux:~$ exit logout
Try it
- Create a user
meerawithuseradd, a home directory, Bash, and the commentMeera Iyer. - Give her the password
Lab.Pass.7withchpasswd, then check its status.
Answer
$ sudo useradd -m -s /bin/bash -c "Meera Iyer" meera $ echo "meera:Lab.Pass.7" | sudo chpasswd $ sudo passwd -S meera meera P 2026-10-21 0 99999 7 -1 $ getent passwd meera meera:x:1003:1003:Meera Iyer:/home/meera:/bin/bash
Changing users: usermod
usermod changes an existing account. The options you'll use:
| Option | Does |
|---|---|
-aG group | Add to a supplementary group |
-s /bin/bash | Change the shell |
-c "text" | Change the comment |
-l newname | Rename the account |
-L / -U | Lock / unlock the password |
-e 2026-12-31 | Expire the whole account on that date |
**Always write -aG, never just -G.** -G alone replaces the user's list of groups with the one you give, silently removing them from everything else, including sudo.
$ sudo usermod -aG adm ravi $ id ravi uid=1002(ravi) gid=1002(ravi) groups=1002(ravi),4(adm)
Making an admin
On Ubuntu, being in the sudo group is what makes someone an admin. Add the user to it, then check what they're allowed to do:
$ sudo usermod -aG sudo asha $ sudo -l -U asha User asha may run the following commands on linux: (ALL : ALL) ALL
Group changes take effect at the user's next login. If Asha is already logged in, she needs to log out and back in before sudo works for her.
Locking and expiring
When someone leaves, lock the account before you delete anything, so you can check what they owned first. chage -l shows the password aging settings, and chage -E sets the date the account stops working:
$ sudo usermod -L meera $ sudo passwd -S meera meera L 2026-10-21 0 99999 7 -1 $ sudo chage -E 2026-12-31 ravi $ sudo chage -l ravi Last password change : Oct 21, 2026 Password expires : never Password inactive : never Account expires : Dec 31, 2026 Minimum number of days between password change : 0 Maximum number of days between password change : 99999 Number of days of warning before password expires : 7
Try it
- Change
asha's shell to Bash (adduseralready did, but practise it) and her comment toAsha Rao, admin. - Unlock
meeraagain.
Answer
$ sudo usermod -s /bin/bash -c "Asha Rao, admin" asha $ sudo usermod -U meera $ sudo passwd -S meera meera P 2026-10-21 0 99999 7 -1 $ getent passwd asha asha:x:1001:1001:Asha Rao, admin:/home/asha:/bin/bash
Managing groups
| Command | Does |
|---|---|
groupadd devs | Create a group |
gpasswd -a user devs | Add a user to it (same as usermod -aG devs user) |
gpasswd -d user devs | Remove a user from it |
groupmod -n newname devs | Rename it |
groupdel devs | Delete it |
getent group devs | Show it and its members |
$ sudo groupadd devs $ sudo gpasswd -a ravi devs Adding user ravi to group devs $ sudo gpasswd -a meera devs Adding user meera to group devs $ getent group devs devs:x:1004:ravi,meera $ sudo gpasswd -d meera devs Removing user meera from group devs $ getent group devs devs:x:1004:ravi
Try it
- Create a group
ops, addashato it, and list its members. - Rename it to
operations.
Answer
$ sudo groupadd ops $ sudo usermod -aG ops asha $ sudo groupmod -n operations ops $ getent group operations operations:x:1005:asha
Deleting users
userdel removes the account. -r also deletes the home directory and mail. Deleting a user doesn't delete files they own elsewhere: those keep the old UID, and ls -l shows a bare number where the name was. Find them first:
$ sudo find / -user meera -not -path "/proc/*" 2> /dev/null /home/meera /home/meera/.bashrc /home/meera/.bash_logout /home/meera/.profile $ sudo userdel -r meera userdel: meera mail spool (/var/mail/meera) not found $ getent passwd meera; echo $? 2
The message about the mail spool is harmless: Ubuntu servers don't give users a local mailbox, so there was nothing to delete. getent returns 2 when there's no such entry. On Ubuntu, deluser --remove-home meera does the same as userdel -r.
Who's logged in?
| Command | Shows |
|---|---|
whoami | Your user name |
w | Who's logged in, from where, since when, and what they're running |
loginctl list-sessions | Every login session, as systemd sees them |
who | Who's logged in (but see below) |
uptime | The same top line as w |
last | Login history |
$ w 12:15:58 up 1:09, 2 users, load average: 0.33, 0.15, 0.05 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT ubuntu pts/1 127.0.0.1 12:15 0.00s 0.02s ? w ubuntu - 11:06 0.00s 0.10s sshd-se $ loginctl list-sessions --no-pager SESSION UID USER SEAT LEADER CLASS TTY IDLE SINCE 15 1000 ubuntu - 177027 user - no - 2 1000 ubuntu - 1134 manager - no - 3 1000 ubuntu - 1249 user - no - 3 sessions listed. $ who
who printed nothing. That's not a mistake: it reads an old file, /run/utmp, that Ubuntu 26.04 no longer writes, as part of moving away from a format that breaks in 2038. Most guides still use who, so remember that on 26.04 the answer is w or loginctl.
last doesn't come with Ubuntu 26.04 any more. Login history moved to a new database to fix a bug that would have broken the old format in 2038, and the command comes in a separate package. If you try it, Ubuntu tells you which one:
$ last Command 'last' not found, but can be installed with: sudo apt install wtmpdb $ sudo apt install -y wtmpdb Installing: wtmpdb ... $ last ubuntu pts/1 127.0.0.1 Wed Oct 21 12:15 - still logged in ubuntu pts/1 127.0.0.1 Wed Oct 21 12:14 - still logged in ubuntu pts/0 127.0.0.1 Wed Oct 21 12:14 - still logged in ubuntu pts/1 127.0.0.1 Wed Oct 21 12:13 - still logged in ubuntu pts/1 127.0.0.1 Wed Oct 21 11:43 - still logged in ubuntu pts/1 127.0.0.1 Wed Oct 21 11:42 - still logged in ... wtmpdb begins Wed Oct 21 11:33:38 2026
When it's installed, it converts the history the old format had already recorded, so you see past logins straight away, and it records every new one from then on. Each line shows the user, the terminal, where they connected from, and when the session started and ended. still logged in means the session hasn't ended yet.
Try it
- How many people are logged in right now, and how long has the machine been up? (One command.)
Answer
$ uptime
12:16:07 up 1:10, 1 user, load average: 0.52, 0.20, 0.07Common mistakes
- **
usermod -Gwithout-a.** It replaces every supplementary group. People lock themselves out ofsudothis way. Always-aG. - **
useraddwithout-mand-s.** You get a user with no home directory and/bin/sh. Useadduserby hand, or always pass both options. - Expecting group changes to work straight away. They apply at the next login. Log out and back in (or
newgrp groupnamein the current shell). - Deleting a user before checking what they owned. Lock first,
find / -user name, then delete. - **Editing
/etc/passwdor/etc/shadowby hand.** Use the tools. If you must,sudo vipwandsudo vigrlock the files and check them, likevisudodoes for sudoers.
Practice
- Create a user
dev1withadduser, no password yet, commentDeveloper One.
Answer
$ sudo adduser --disabled-password --comment "Developer One" dev1 $ getent passwd dev1 dev1:x:1003:1003:Developer One:/home/dev1:/bin/bash
- Put
dev1andraviin thedevsgroup, without removing them from any other group.
Answer
$ sudo usermod -aG devs dev1 $ getent group devs devs:x:1004:ravi,dev1 $ id dev1 uid=1003(dev1) gid=1003(dev1) groups=1003(dev1),100(users),1004(devs)
ravi is already in it from earlier.
- Set
dev1's password toFirst.Day.1, then log in asdev1withsuand print the groups.
Answer
$ echo "dev1:First.Day.1" | sudo chpasswd ubuntu@linux:~$ su - dev1 Password: dev1@linux:~$ groups dev1 users devs dev1@linux:~$ exit logout
- List every human user on the system (UID 1000 or above, except
nobody).
Answer
$ awk -F: '$3 >= 1000 && $1 != "nobody" {print $1, $3}' /etc/passwd
ubuntu 1000
asha 1001
ravi 1002
dev1 1003awk splits each line on : (-F:) and prints the name and UID when the third field is at least 1000. It's a whole language of its own, but this one pattern is worth copying.
- Make
dev1's account expire at the end of the year, then show the setting.
Answer
$ sudo chage -E 2026-12-31 dev1 $ sudo chage -l dev1 | grep "Account expires" Account expires : Dec 31, 2026
- Remove
dev1completely, including the home directory, then show that the home directory is gone.
Answer
$ sudo userdel -r dev1 userdel: dev1 mail spool (/var/mail/dev1) not found $ ls /home asha ravi ubuntu
Cheat sheet
| Command | What it does |
|---|---|
id, id user | UID, GID and groups |
/etc/passwd, /etc/shadow, /etc/group | Users, password hashes, groups |
getent passwd user, getent group g | Look up a user or group |
sudo adduser --disabled-password --comment "Name" user | Create a user (Ubuntu's friendly way) |
sudo useradd -m -s /bin/bash -c "Name" user | Create a user (exact control) |
sudo passwd user, echo "user:pw" | sudo chpasswd | Set a password |
sudo passwd -S user | Password status (P, L, NP) |
su - user | Become another user |
sudo usermod -aG group user | Add to a group (always -a) |
sudo usermod -s, -c, -l, -L, -U | Shell, comment, rename, lock, unlock |
sudo chage -l user, chage -E date user | Show aging, set account expiry |
sudo groupadd, gpasswd -a/-d, groupmod -n, groupdel | Manage groups |
sudo userdel -r user | Delete a user and their home |
who, w, uptime | Who's on, what they're doing |
last | Login history (install wtmpdb on 26.04) |
← Clean up a messy folderFile permissions: chmod and chown →