Check Last Password Change and Expiration Date in Linux

Deepak Prasad
Tested on RHEL 10.2 (Coughlan)
Package shadow-utils 4.15.0-11.el10
Applies to RHEL, Rocky Linux, AlmaLinux, Fedora, Debian, Ubuntu, and other Linux distributions with shadow password support
Privilege sudo or root to inspect other users; users can run chage -l on their own account
Scope Read last password change, expiration, and status for local Linux accounts with chage, passwd -S, and /etc/shadow. Does not cover setting password-aging policy or checking AD/LDAP password expiry from Linux.
Related guides chage command
Implement password policy in RHEL
Add user to group in Linux
sudo command

To see when a local user's password was last changed and when it expires, run chage -l USERNAME. Last password change is the date recorded in /etc/shadow. Password expires is derived from the last-change date and maximum password age; when password aging is disabled or unlimited, it is shown as never. Account expires is a separate calendar limit on the account itself.


Quick reference: password age and expiration commands

Task Command
Check all aging information sudo chage -l USER
Use ISO dates sudo chage -i -l USER
Check password status sudo passwd -S USER
Check status for all local users sudo passwd -S -a
Read shadow entry sudo getent shadow USER
Grep shadow file sudo grep '^USER:' /etc/shadow

Check last password change with chage

chage -l lists every aging field for a local account from /etc/shadow.

bash
sudo chage -l pwcheck

Sample output:

output
Last password change					: Aug 16, 2026
Password expires					: Nov 14, 2026
Password inactive					: never
Account expires						: never
Minimum number of days between password change		: 0
Maximum number of days between password change		: 90
Number of days of warning before password expires	: 7

The Last password change line is what most administrators need. Locale-specific month names can make scripting awkward, so use ISO dates when you plan to parse the output:

bash
sudo chage -i -l pwcheck

Sample output:

output
Last password change					: 2026-08-16
Password expires					: 2026-11-14
Password inactive					: never
Account expires						: never
Minimum number of days between password change		: 0
Maximum number of days between password change		: 90
Number of days of warning before password expires	: 7

Do not rely on chage -l USER | head -1 as a shortcut. The full chage -l output already includes expiration, inactivity, and account-expiry lines you need in the next section.


Check when a password expires

Read the same chage -l output and focus on four lines:

  • Last password change — date the stored password hash was last updated
  • Password expires — derived from last-change date and maximum password age (-M policy); shown as never when aging is disabled or unlimited
  • Password inactive — date when the post-expiry inactivity period ends; the underlying inactivity setting is a number of days after password expiration
  • Account expires — calendar date when the account itself is disabled, independent of the password

These settings are easy to confuse:

Password expiration is controlled by maximum password age. After the password expires, the user is required to change it before continuing to use the account.

Password inactivity is the grace period after password expiration. Once that period also expires, the user can no longer log in with the expired password and administrator intervention may be required. The chage -I option sets the number of days for this grace period.

Account expiration disables the account on a fixed date regardless of password age.

To change maximum age, warning days, or account expiry, see the chage command guide. This article focuses on reading current values.


Check password status with passwd -S

passwd -S prints a one-line summary: status code, last change, and aging numbers.

bash
sudo passwd -S pwcheck

Sample output:

output
pwcheck P 2026-08-16 0 90 7 -1

The seven fields are username, status, last change, minimum age, maximum age, warning period, and inactivity period.

Current shadow-utils status codes:

  • P — usable password
  • L — locked password
  • NP — no password

A locked system account shows L in the status column. On the lab host, bin is an example:

bash
sudo passwd -S bin

Sample output:

output
bin L 2025-04-08 0 99999 7 -1

The third field matches the Last password change date from chage -l for the same user.


Check password expiration for all local users

List every local account in one pass:

bash
sudo passwd -S -a

Sample output (trimmed):

output
root P 2026-08-03 0 99999 7 -1
bin L 2025-04-08 0 99999 7 -1
pwcheck P 2026-08-16 0 90 7 -1

Each line gives status and aging numbers but not the human-readable Password expires date. When you need that detail for several users, loop chage -i -l over accounts listed in /etc/passwd:

bash
for u in $(cut -d: -f1 /etc/passwd); do
  echo "=== $u ==="
  sudo chage -i -l "$u" 2>/dev/null | grep -E '^(Last password change|Password expires)'
done

Check last password change in /etc/shadow

The third colon-separated field in /etc/shadow stores the last password change as a day count since 1970-01-01.

bash
sudo grep '^pwcheck:' /etc/shadow

Sample output (hash trimmed):

output
pwcheck:$y$j9T$YPIWaN6XoDLI1FgCySgko0$I.iyvFIfpwyZFC7UzgH5B2Ka0F2swsWhyr.zXtqs.m4:20681:0:90:7:::

Field 3 (20681 here) is the last-change counter:

text
username:hash:LAST_CHANGE:min:max:warn:inact:expire:reserved
                              ^
                              last password change (days since 1970-01-01)

Convert that counter to a calendar date when you are reading shadow directly:

bash
date -d '1970-01-01 +20681 days' +%Y-%m-%d

Sample output:

output
2026-08-16

For day-to-day checks, chage -l or chage -i -l is easier than decoding shadow fields by hand.


Can Linux show the exact password change time?

No — not from shadow data alone. /etc/shadow records last change as a day number, not a timestamp. chage, passwd -S, and a decoded shadow field therefore report the date, not the hour, minute, or second.

If auditd or journald captured the original passwd or chage event, those logs may include a precise timestamp. That is separate historical logging and may no longer exist after rotation or on hosts without auditing enabled.


Why the recorded last-change date can be modified

chage, passwd -S, and /etc/shadow report the account's current stored last-change value. A privileged administrator can change that field without changing the password hash:

bash
sudo chage -d 2026-08-10 pwcheck

After that command, chage -i -l shows the new date:

bash
sudo chage -i -l pwcheck | head -1

Sample output:

output
Last password change					: 2026-08-10

That update does not prove the password itself was changed on that day. When you need historical evidence of password-change events, check audit or journal records if your site collects them — not the shadow field alone.


Local users vs LDAP and Active Directory users

chage reads local shadow password information. It does not report password-aging policy obtained from external identity providers such as LDAP or Active Directory.

If a user authenticates through SSSD or another NSS source and has no local /etc/shadow entry, chage -l may fail or show nothing useful. Check password expiry on the directory server or through your identity stack instead. Joining Linux to AD is covered in join Linux to a Windows domain; AD password expiry from Linux deserves its own focused guide.


References


Summary

To check last password change and expiration on a local Linux account, start with sudo chage -l USERNAME. Add -i when you want ISO dates for scripts. The Last password change line comes from /etc/shadow; Password expires is derived from that date and maximum password age, or shows never when aging is unlimited; Account expires is a separate account-level limit.

sudo passwd -S USER gives a compact status line with current P, L, or NP codes. Use sudo passwd -S -a to scan every local user quickly, then chage -i -l when you need full expiry dates. Shadow field 3 holds the same last-change counter if you are already reading /etc/shadow directly.

Shadow data stores a date, not a clock time, and root can rewrite the last-change field with chage -d without changing the password. Treat chage and passwd -S as the authoritative current record for local accounts, and use directory tools for LDAP or AD users. To set aging policy, open the chage command guide instead of this page.


Frequently Asked Questions

1. What is the fastest way to check last password change on Linux?

Run sudo chage -l USERNAME. The Last password change line shows the date stored in /etc/shadow. Add -i for ISO YYYY-MM-DD dates that are easier to script.

2. How do I check password expiration for all local users?

Run sudo passwd -S -a. Each line lists username, status, last change, minimum age, maximum age, warning period, and inactivity period.

3. Can Linux show the exact time a password was changed?

No. /etc/shadow stores the last change as a day count since 1970-01-01, so chage and passwd -S report a date, not an hour or minute. Audit or journal logs may retain a timestamp if they captured the original change event.

4. Does chage work for Active Directory or LDAP users?

chage reads local /etc/shadow data only. It does not report password aging obtained from LDAP, Active Directory, or other external identity providers. Check those systems through their own tools or directory queries.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux
  • Shell Script
  • System Administration