A security-focused guide to passwd — covering immediate account lockouts, password aging enforcement, and service account hardening for production Linux servers.
What is passwd?
The passwd command manages user account passwords and authentication policy on Linux. Beyond simply changing passwords, it controls account locking, password expiry, and minimum/maximum age enforcement — all of which are critical security controls on production servers. For incident response, passwd -l username is the fastest way to disable a compromised account without deleting it, preserving its files and process ownership for forensic examination while immediately blocking interactive logins. For hardening, applying passwd -l to all service accounts ensures that accounts used only for running services cannot be used for interactive login even if credentials are somehow obtained or enumerated.
Syntax
passwd [options] [username]
passwd # Change current user's password
passwd username # Change another user's password (root only)
passwd -l username # Lock account
passwd -u username # Unlock account
passwd -e username # Force password change at next login
passwd -S username # Show account statusWithout arguments, passwd changes the calling user’s own password. With a username argument (root-only), it modifies another account. The -l (lock) and -u (unlock) flags are the most security-relevant options for incident response. passwd -S shows the current status — locked, expired, or active.
Key Options and Flags
| Flag / Parameter | Description | Security Note |
|---|---|---|
-l | Lock the account — prepends '!' to the password hash in /etc/shadow, preventing authentication | Fastest incident response tool for disabling a compromised account while preserving forensic evidence |
-u | Unlock a previously locked account | Only unlock after the cause of the compromise has been fully investigated and remediated |
-e | Expire the password immediately — forces change at next login | Use after any suspected credential exposure to force re-authentication with a new password |
-S | Display account status: locked/unlocked, date of last change, expiry settings | Use during audits to verify service accounts are locked as expected |
-n days | Minimum number of days between password changes | — |
-x days | Maximum number of days before the password must be changed | — |
-w days | Number of days before expiry that a warning is given | — |
Common Use Cases
Immediately Lock a Compromised Account
When unauthorized access to an account is detected — via last, lastb, or an active connection in who — the immediate response is to lock the account with passwd -l. This prevents further authentication without deleting the account, which would destroy files and process ownership needed for forensics. Follow up by killing any active sessions with pkill -u username.
passwd -l compromised_user
pkill -u compromised_user
passwd -S compromised_userLock All Service Accounts to Prevent Interactive Login
Service accounts — www-data, nginx, mysql, redis, postgres, nobody — should never be used for interactive SSH login. Lock them as a baseline hardening step. An attacker who obtains these credentials cannot use them to SSH in if the accounts are locked.
for user in www-data nginx mysql redis postgres daemon bin sys; do
passwd -l $user
echo "Locked: $user"
doneAudit Password Status of All Human Accounts
Regular password status audits catch accounts with expired passwords (potential abandoned accounts), accounts with no password set (critical vulnerability), and accounts that have never had their password changed since creation. The passwd -S output for each account provides this information.
awk -F: '$3 >= 1000 {print $1}' /etc/passwd | while read user; do
echo -n "$user: "; passwd -S "$user"
doneSecurity Relevance: Account Control as a Defense Layer
Password policy and account locking are foundational identity controls. Attackers who obtain credentials — through phishing, log exposure, credential stuffing, or database leaks — can only exploit them if the account is active and the password is valid. A disciplined account hygiene policy — all service accounts locked with passwd -l, all human accounts subject to password expiry via chage, immediate lockout on any indicator of compromise — significantly reduces the window of opportunity after a credential breach. The passwd -l command is the fastest defensive action available during an active incident, taking effect immediately without requiring a service restart, configuration reload, or scheduled maintenance window. Service accounts that have never needed interactive login should be permanently locked as a baseline hardening step, not just in response to an incident.
- Locking root with passwd -l and having no other sudo-capable accounts will permanently lock you out of the server
- passwd -l does NOT terminate existing sessions — use pkill -u or kill -9 to kill active processes after locking
- Service accounts with /bin/bash or /bin/sh as their shell can be used for interactive login if not locked — verify with grep www-data /etc/passwd
- Accounts with an empty password field in /etc/shadow (represented by a blank or '!') may be accessible depending on PAM configuration
- Password aging set too aggressively on service accounts can lock them out automatically, causing service outages
Practical Examples
Lock a compromised account and kill all its active sessions
passwd -l targetuser
who | grep targetuser
pkill -9 -u targetuser
passwd -S targetuserLocks the account immediately, checks for active sessions, terminates all of them, and confirms the lock status. This four-command sequence is the standard immediate response to a suspected account compromise.
Find all accounts with no password set (critical security gap)
awk -F: '($2 == "" || $2 == "*" || $2 == "!") && $3 >= 1000' /etc/shadowAn empty password field in /etc/shadow means the account can potentially be accessed without a password depending on PAM configuration. The ‘!’ prefix indicates a locked account (safe). The ‘*’ indicates no password and no login capability (also safe for service accounts). An empty field is the dangerous case.
Force password expiry for all human accounts after a credential breach
awk -F: '$3 >= 1000 && $1 != "nobody" {print $1}' /etc/passwd | while read user; do
passwd -e "$user"
echo "Expired: $user"
doneForces all human accounts to change their password at next login. Use this immediately after a suspected credential exposure — for example, after discovering that /etc/shadow was readable by a compromised service account.
Troubleshooting Common Issues
Problem: passwd -l does not prevent a user from logging in via SSH key
Solution: passwd -l only blocks password-based authentication. SSH key authentication is not controlled by /etc/shadow. To fully block an account, also disable its shell (usermod -s /usr/sbin/nologin username) and remove or rename its authorized_keys file.
Problem: Service fails to start after locking the service account
Solution: The service itself should not be affected by account locking — locking prevents interactive login, not process execution. If the service is failing, the issue is likely elsewhere (permissions, missing files). Verify the service’s systemd unit runs under the correct User= directive and the account’s home directory is intact.
Problem: passwd -S shows 'L' (locked) but user can still log in
Solution: The user may be authenticating via LDAP, SSSD, or another PAM module that bypasses /etc/shadow. Check /etc/nsswitch.conf for the passwd and shadow entries. Also verify that SSH AllowUsers or AllowGroups is not being used to enforce access separately.
Summary
The passwd command is the primary tool for account lifecycle security on Linux: locking compromised accounts during incidents, hardening service accounts to prevent interactive login, and enforcing password policy for human users. Develop the habit of locking all service accounts as a baseline — their credentials are never needed interactively — and use passwd -l as the first response action when any account compromise is suspected.
- Lock all service accounts (
www-data,nginx,mysql, etc.) as a baseline — they should never be used for interactive login passwd -lis the fastest incident response action for a compromised account — use it immediately, then kill active sessions- Account locking does NOT block SSH key auth — pair it with
usermod -s /usr/sbin/nologinfor complete lockout
Related Commands
id to verify user identity and group membership • last for login history forensics • lastb to audit failed login attempts • sudo privilege auditing
Are Your Service Accounts Locked Down?
INTRAM locks all non-interactive service accounts, enforces password policy for human accounts, and responds immediately to any credential compromise indicator on managed servers.
Request Account Hardening