cat /etc/passwd lists every user account on a Linux system, and getent passwd does the same while also including users from directory services like LDAP. Both take a second and both will show you thirty-odd accounts on a box where you thought there were two. That is normal - most Linux users are not people. They are service accounts created by packages, each one existing so a daemon can run without root. The useful skill is not running the command; it is reading the output and knowing which of those accounts can log in, which are dormant by design, and which one is a surprise.
This looks like a trivia question with a one-line answer. It is actually the first step of every server security review, because a list of accounts is a list of ways in.
Table of contents
- The commands
- Reading a /etc/passwd line
- The query that actually answers the question
- Most of these accounts are supposed to be there
- passwd does not tell you about passwords
- The stale account is the realistic risk
- How this fits the rest of the stack
- FAQ
The commands
# Every local account.
cat /etc/passwd
# Local accounts plus LDAP/NIS. Prefer this one.
getent passwd
# Just the usernames.
cut -d: -f1 /etc/passwd
# Who is logged in right now - a different question.
who
w
Use getent passwd by default. On a standalone box it reads /etc/passwd and the result is identical. On a machine joined to a directory service it also returns accounts that cat will never show you - and those are exactly the accounts a review needs to see.
Note that who and w answer a different question: who has a session open now, not who has an account. People conflate the two, and the gap between them is where dormant accounts live.
Reading a /etc/passwd line
Seven colon-separated fields:
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
| | | | | | |
| | | | | | +-- login shell
| | | | | +--------------- home directory
| | | | +------------------------- comment / full name
| | | +------------------------------- GID
| | +---------------------------------- UID
| +------------------------------------- password (x = see /etc/shadow)
+------------------------------------------- username
Two fields carry almost all the signal.
The shell. /usr/sbin/nologin or /bin/false means the account cannot log in interactively. That is deliberate and correct for a service account. /bin/bash on a service account is a finding.
The UID. The convention is nearly universal:
- 0 - root. There should be exactly one.
- 1-999 - system and service accounts, created by packages.
- 1000+ - real human users.
- 65534 - nobody, the deliberately powerless account.
That convention is what turns thirty lines of noise into a two-line answer.
The query that actually answers the question
You almost never want all users. You want the humans:
# Accounts with UID >= 1000 - the real people.
awk -F: '$3 >= 1000 && $3 != 65534 {print $1}' /etc/passwd
# Accounts that can actually log in - the security-relevant set.
awk -F: '$7 !~ /(nologin|false)$/ {print $1, $7}' /etc/passwd
# Anything with UID 0 - there had better be only root.
awk -F: '$3 == 0 {print $1}' /etc/passwd
That last one is worth running on any box you inherited. A second UID-0 account is a root-equivalent backdoor that does not look like one at a glance, because it has a different name. awk -F: '$3 == 0' is a two-second check that finds it.
The second query is the real audit: which accounts have a usable shell? Every one of those is a login path, and each should have an owner you can name.
Most of these accounts are supposed to be there
A fresh Ubuntu install has around thirty accounts before you create any. www-data, sshd, systemd-resolve, messagebus, nobody. None of them are suspicious.
They exist because of the principle that makes Linux servers survivable: a daemon should run as an account that can touch only what it needs. If nginx is compromised, the attacker gets www-data - which can read your web root and essentially nothing else. If nginx ran as root, the same bug would be a total compromise.
So the long account list is a feature. What matters is whether each account matches its purpose:
- A service account with
nologinand a UID under 1000 - normal. - A service account with
/bin/bash- why? - A human account for someone who left last year - remove it.
- A UID 0 account that is not root - urgent.
- An account you cannot explain at all - the one to investigate.
passwd does not tell you about passwords
A common misreading: the x in field two is not a password, it is a marker meaning the hash lives in /etc/shadow. /etc/passwd is world-readable - every user on the box can read it - so no secret has been kept there for decades.
# Requires root. Shows lock status, not the hash in usable form.
sudo passwd -S alice
# All accounts and their password status.
sudo passwd -Sa
The status letter is the useful part: P means a usable password is set, L means locked, NP means no password at all. An NP account is an open door and passwd -Sa is how you find it.
Worth noting that on a properly configured server, password status is often irrelevant because password authentication over SSH is disabled entirely and only keys are accepted. If that is your setup, the account audit that matters is ~/.ssh/authorized_keys for every account with a shell - a key in there is a login, regardless of what passwd -S says.
The stale account is the realistic risk
In practice, the dangerous account on most servers is not an attacker’s backdoor. It is the account belonging to someone who left, still holding an authorized key, still able to log in, belonging to nobody’s mental model of who has access.
The audit worth running periodically:
- List humans:
awk -F: '$3 >= 1000 && $3 != 65534' /etc/passwd. - For each, can they log in? Check the shell and
authorized_keys. - For each, do they still work here?
- Check sudo:
getent group sudoand read/etc/sudoers.d/. - Remove or lock anything that fails those questions.
This is the sort of task that exists only because someone is hand-managing user accounts on a long-lived box. It is real work, it is never urgent until it is, and it does not make your product better - which is the honest argument for not managing servers by hand at all.
How this fits the rest of the stack
Auditing accounts is unbilled work that quietly eats an afternoon a quarter, and it is the kind of work that only exists because a machine is being tended by hand. It is worth knowing what the alternative costs before deciding it is not for you. The RunxBuild hosting calculator lays out the service, database, storage, and bandwidth as separate line items so the comparison is against a real number rather than a habit, and the RunxBuild dashboard is where access and usage are visible in one place.
Useful related references:
- tar Command in Linux: Create, Extract, List, Compress Archives
- How to Rename a File in Linux: mv, rename, and git mv
- hostnamectl set-hostname: How to Set the Hostname in Linux
- Database user management on RunxBuild
FAQ
How do I list all users in Linux?
Use getent passwd for the complete picture, including accounts from LDAP or other directory services, or cat /etc/passwd for local accounts only. For just the usernames, cut -d: -f1 /etc/passwd. Expect around thirty accounts on a fresh server - the great majority are service accounts created by packages, not people.
What is the difference between /etc/passwd and getent passwd?
/etc/passwd is the local account file. getent passwd queries every configured name service, so it returns local accounts plus any from LDAP, NIS, or similar directories. On a standalone machine the output is identical. On a domain-joined machine, cat misses accounts that can actually log in - which makes getent the right default for any audit.
How do I list only real human users in Linux?
Filter by UID: awk -F: '$3 >= 1000 && $3 != 65534 {print $1}' /etc/passwd. The convention is that UID 0 is root, 1-999 are system and service accounts, and 1000 and above are humans. UID 65534 is nobody, which is excluded explicitly because it sits above the threshold but is not a person.
Why are there so many users on my Linux server?
Because most Linux users are not people - they are service accounts so each daemon can run with only the permissions it needs. If nginx runs as www-data and is compromised, the attacker gets www-data, not root. The long list is a security feature. What matters is that each account matches its purpose: a service account should have nologin as its shell, not /bin/bash.
How can I tell which Linux accounts can actually log in?
Check the shell field: awk -F: '$7 !~ /(nologin|false)$/ {print $1, $7}' /etc/passwd lists accounts with a usable shell. Also run sudo passwd -Sa to see password status - NP means no password is set at all. And check ~/.ssh/authorized_keys for each of those accounts, since a key there is a login regardless of password status.