Nandishwar Singh

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

  1. Users are numbers
  2. /etc/passwd: the list of users
  3. /etc/shadow: the passwords
  4. Groups
  5. Creating users
  6. Changing users: usermod
  7. Managing groups
  8. Deleting users
  9. Who's logged in?
  10. Common mistakes
  11. Practice
  12. 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
Fieldubuntu's valueMeans
1ubuntuUser name
2xThe password is kept in /etc/shadow instead
31000UID
41000Primary group's GID
5UbuntuFull name or comment
6/home/ubuntuHome directory
7/bin/bashLogin 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

  1. What's the UID of the www-data user, and what's its shell?
  2. 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:

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" asha

And 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 successfully

In 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

  1. Create a user meera with useradd, a home directory, Bash, and the comment Meera Iyer.
  2. Give her the password Lab.Pass.7 with chpasswd, 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:

OptionDoes
-aG groupAdd to a supplementary group
-s /bin/bashChange the shell
-c "text"Change the comment
-l newnameRename the account
-L / -ULock / unlock the password
-e 2026-12-31Expire 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

  1. Change asha's shell to Bash (adduser already did, but practise it) and her comment to Asha Rao, admin.
  2. Unlock meera again.
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

CommandDoes
groupadd devsCreate a group
gpasswd -a user devsAdd a user to it (same as usermod -aG devs user)
gpasswd -d user devsRemove a user from it
groupmod -n newname devsRename it
groupdel devsDelete it
getent group devsShow 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

  1. Create a group ops, add asha to it, and list its members.
  2. 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?

CommandShows
whoamiYour user name
wWho's logged in, from where, since when, and what they're running
loginctl list-sessionsEvery login session, as systemd sees them
whoWho's logged in (but see below)
uptimeThe same top line as w
lastLogin 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

  1. 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.07

Common mistakes

Practice

  1. Create a user dev1 with adduser, no password yet, comment Developer One.
Answer
$ sudo adduser --disabled-password --comment "Developer One" dev1
$ getent passwd dev1
dev1:x:1003:1003:Developer One:/home/dev1:/bin/bash
  1. Put dev1 and ravi in the devs group, 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.

  1. Set dev1's password to First.Day.1, then log in as dev1 with su and 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
  1. 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 1003

awk 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.

  1. 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
  1. Remove dev1 completely, 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

CommandWhat it does
id, id userUID, GID and groups
/etc/passwd, /etc/shadow, /etc/groupUsers, password hashes, groups
getent passwd user, getent group gLook up a user or group
sudo adduser --disabled-password --comment "Name" userCreate a user (Ubuntu's friendly way)
sudo useradd -m -s /bin/bash -c "Name" userCreate a user (exact control)
sudo passwd user, echo "user:pw" | sudo chpasswdSet a password
sudo passwd -S userPassword status (P, L, NP)
su - userBecome another user
sudo usermod -aG group userAdd to a group (always -a)
sudo usermod -s, -c, -l, -L, -UShell, comment, rename, lock, unlock
sudo chage -l user, chage -E date userShow aging, set account expiry
sudo groupadd, gpasswd -a/-d, groupmod -n, groupdelManage groups
sudo userdel -r userDelete a user and their home
who, w, uptimeWho's on, what they're doing
lastLogin history (install wtmpdb on 26.04)