Linux stores user accounts in
/etc/passwd
. Every user on the system, whether a human who logs in via SSH or a system account that runs a service, has an entry in this file. Listing users means reading this file and filtering it to find what you need. There are several ways to do this depending on whether you want all users, only human users, currently logged-in users, or users with specific privileges.
This guide covers each method with practical examples you can run on any Linux server.
Listing all users from /etc/passwd#
The most direct way to see every user account on the system:
cat /etc/passwd
Each line represents one user. The format is:
username:password:UID:GID:comment:home_directory:shell
For example:
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
john:x:1001:1001:John Smith:/home/john:/bin/bash
The fields that matter most:
- username (field 1) – the account name
- UID (field 3) – the numeric user ID. Root is always 0. System accounts are typically below 1000. Human users start at 1000 on most distributions.
- home_directory (field 6) – where the user’s files live
- shell (field 7) – the shell assigned to the user.
/bin/bashor/bin/zshmeans the user can log in interactively./usr/sbin/nologinor/bin/falsemeans the account cannot log in.
The
x
in the password field means the actual password hash is stored in
/etc/shadow
, which is only readable by root.
Extract just the usernames
cut -d: -f1 /etc/passwd
The
-d:
flag sets the delimiter to colon. The
-f1
flag extracts the first field (username). This gives you a clean list of every username on the system, one per line.
Extract usernames with UIDs
awk -F: '{print $1, $3}' /etc/passwd
Output:
root 0
daemon 1
bin 2
www-data 33
john 1001
jane 1002
This is useful for quickly seeing which accounts are system accounts (UID below 1000) and which are human users (UID 1000 and above).
Sort by UID
sort -t: -k3 -n /etc/passwd
This sorts the passwd file by the third field (UID) numerically. System accounts appear first, followed by human users in the order they were created.
Using getent passwd#
getent
queries the system’s name service databases, which includes
/etc/passwd
but also LDAP, NIS, and other directory services if configured. On a server that authenticates against Active Directory or LDAP,
cat /etc/passwd
only shows local accounts.
getent passwd
shows all accounts the system knows about.
getent passwd
The output format is identical to
/etc/passwd
. If your server only uses local authentication (no LDAP, no AD),
getent passwd
and
cat /etc/passwd
produce the same results.
Look up a specific user
getent passwd john
This returns the passwd entry for
john
if the account exists, or nothing if it does not. This is a quick way to check whether a user account exists on the system.
Listing only human users#
A typical Linux server has dozens of system accounts (daemon, nobody, www-data, mysql, postfix, etc.) and only a few human users. Filtering out system accounts makes the user list more useful.
Filter by UID range
On most Linux distributions (RHEL, CentOS, Rocky Linux, Ubuntu, Debian), human users have UIDs starting at 1000. System accounts have UIDs below 1000.
awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd
The
$3 >= 1000
condition filters for UIDs at or above 1000. The
$3 < 65534
condition excludes the
nobody
account (which has UID 65534 on most systems).
On older RHEL/CentOS systems, human UIDs started at 500 instead of 1000. Check your system’s
/etc/login.defs
for the
UID_MIN
value:
grep UID_MIN /etc/login.defs
Filter by shell
Human users typically have an interactive shell (
/bin/bash
,
/bin/zsh
,
/bin/sh
). System accounts have
/usr/sbin/nologin
or
/bin/false
. Filtering by shell is another way to find human users:
grep -E '/bin/(bash|zsh|sh)$' /etc/passwd | cut -d: -f1
This finds all accounts with an interactive shell. It is not perfect since some system accounts may have a real shell assigned, but it covers the common case.
Filter by home directory
Human users typically have home directories under
/home/
. System accounts have home directories in other locations (
/var/www
,
/var/lib/mysql
,
/root
).
awk -F: '$6 ~ /^\/home/ {print $1}' /etc/passwd
This lists users whose home directory starts with
/home/
.
Using compgen
compgen -u
This is a Bash built-in that lists all usernames known to the system. The output is a plain list of usernames, one per line. It queries the same sources as
getent passwd
but only returns the username, not the full passwd entry.
Combining filters
You can combine UID and shell filters for a more precise list of actual human users who can log in:
awk -F: '$3 >= 1000 && $3 < 65534 && $7 !~ /nologin|false/ {print $1, $3, $7}' /etc/passwd
This shows only users with UID 1000+ who have an interactive shell. On a well-configured server, this should match exactly the people who have SSH access to the machine.
Checking user account details#
Full details for a specific user
id john
uid=1001(john) gid=1001(john) groups=1001(john),27(sudo),33(www-data)
Check when a password was last changed
sudo chage -l john
Output:
Last password change : Mar 15, 2026
Password expires : never
Password inactive : never
Account expires : never
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
This is useful for security audits. Accounts with passwords that have not been changed in years, or accounts set to never expire, may need attention.
Check if an account is locked
sudo passwd -S john
Output:
john P 03/15/2026 0 99999 7 -1
The second field indicates the account status:
P
means the password is set (account is active),
L
means the account is locked, and
NP
means no password is set.
Scripting user lists#
Export human users to a file
awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd > /tmp/user-list.txt
Compare users across two servers
If you manage multiple servers and want to verify that user accounts are consistent:
# On server A
awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd | sort > /tmp/users-a.txt
# On server B (run via SSH)
ssh user@server-b "awk -F: '\$3 >= 1000 && \$3 < 65534 {print \$1}' /etc/passwd" | sort > /tmp/users-b.txt
# Compare
diff /tmp/users-a.txt /tmp/users-b.txt
Lines starting with
<
exist only on server A. Lines starting with
>
exist only on server B. If both servers should have the same users, any differences need investigation.
Find users who have never logged in
for user in $(awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd); do
if ! last "$user" | grep -q "pts\|tty"; then
echo "$user has never logged in"
fi
done
Accounts that exist but have never been used may be stale accounts from former employees or test accounts that were never cleaned up. These are a security risk because an attacker who discovers the credentials can use them without raising suspicion.
Counting users#
Total accounts
wc -l /etc/passwd
Or more precisely, counting only non-empty lines:
getent passwd | wc -l
Only human users
awk -F: '$3 >= 1000 && $3 < 65534' /etc/passwd | wc -l
On a typical web server, you might have 30-50 total accounts but only 2-5 human users.
Listing currently logged-in users#
These commands show who is connected to the server right now, not who has an account.
who
who
Output:
john pts/0 2026-03-30 09:15 (10.0.1.50)
jane pts/1 2026-03-30 10:22 (10.0.1.51)
This shows each logged-in user, their terminal, when they logged in, and where they connected from. Each line is one active session. A user with two SSH sessions open appears twice.
w
w
Output:
10:45:23 up 42 days, 3:15, 2 users, load average: 0.12, 0.08, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
john pts/0 10.0.1.50 09:15 0.00s 0.05s 0.00s w
jane pts/1 10.0.1.51 10:22 23:10 0.02s 0.02s vim config.php
w
shows everything
who
shows plus the system uptime, load average, idle time for each session, and what command each user is currently running. This is more useful than
who
for checking whether someone is actively working or has an idle session.
users
users
Output:
john jane
The simplest form. Just the usernames of logged-in users, space-separated on one line. No details about terminals or login times.
Listing recent logins#
last
last
This reads
/var/log/wtmp
and shows a history of logins and logouts:
john pts/0 10.0.1.50 Mon Mar 30 09:15 still logged in
jane pts/1 10.0.1.51 Mon Mar 30 08:00 - 09:30 (01:30)
john pts/0 10.0.1.50 Sun Mar 29 14:22 - 17:45 (03:23)
reboot system boot 5.14.0-362 Sat Feb 15 07:30 still running
The
reboot
entries show when the system was restarted. The time in parentheses shows session duration.
Filter by user
last john
Shows only login history for
john
.
Failed login attempts
lastb
This reads
/var/log/btmp
and shows failed login attempts. Requires root. Useful for checking whether someone is trying to brute-force SSH access to the server. If you see hundreds of failed attempts from various IPs, that is normal internet background noise. Fail2ban handles this automatically by banning IPs after repeated failures.
sudo lastb | head -20
Listing users with sudo access#
Knowing which users can run commands as root is important for security auditing.
Check the sudoers file
sudo cat /etc/sudoers
This shows the main sudoers configuration. Look for lines like:
root ALL=(ALL:ALL) ALL
%sudo ALL=(ALL:ALL) ALL
%wheel ALL=(ALL:ALL) ALL
The
%sudo
and
%wheel
lines mean any user in the
sudo
or
wheel
group has full sudo access. Which group is used depends on the distribution: Ubuntu uses
sudo
, RHEL/Rocky Linux uses
wheel
.
List members of the sudo/wheel group
# Ubuntu/Debian
getent group sudo
# RHEL/Rocky Linux/CentOS
getent group wheel
Output:
wheel:x:10:john,jane
This shows that
john
and
jane
are in the
wheel
group and can use
sudo
.
Check sudoers.d directory
Additional sudo rules can be added in
/etc/sudoers.d/
:
sudo ls -la /etc/sudoers.d/
Each file in this directory may grant sudo access to specific users or groups. Check each one to get the complete picture of who has elevated privileges.
On Hostney, SSH access and user permissions are managed through the control panel. Each hosting account has its own isolated environment, so user management is scoped to the account level rather than the server level. For managing database users specifically, see How to show and manage MySQL users.
Listing users in a specific group#
See all groups and their members
cat /etc/group
The format is
groupname:password:GID:members
. The members field is a comma-separated list of usernames.
List members of a specific group
getent group www-data
Output:
www-data:x:33:john,deploy
List all groups a user belongs to
groups john
Output:
john : john sudo www-data
Or with numeric GIDs:
id john
Output:
uid=1001(john) gid=1001(john) groups=1001(john),27(sudo),33(www-data)
The
id
command is the most detailed. It shows the user’s UID, primary GID, and all supplementary groups with both names and numeric IDs. This is useful for verifying file permission issues, since file access is determined by the user’s UID and group memberships.
Quick reference#
# All usernames
cut -d: -f1 /etc/passwd
# All users (including LDAP/AD)
getent passwd | cut -d: -f1
# Human users only (UID >= 1000)
awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd
# Check if a user exists
getent passwd username
# Currently logged-in users
who
w
# Login history
last
last username
# Failed login attempts
sudo lastb
# Users with sudo access (Ubuntu)
getent group sudo
# Users with sudo access (RHEL/Rocky)
getent group wheel
# Groups a user belongs to
id username
# Count human users
awk -F: '$3 >= 1000 && $3 < 65534' /etc/passwd | wc -l