| Tested on | Ubuntu 25.04 (Plucky Puffin) |
|---|---|
| Package | shadowshadow-utils |
| Applies to | Ubuntu, Debian, RHEL, Fedora, SUSE |
| Privilege | sudo or root |
| Man page | chage(1) |
| Scope | chage views and edits password aging fields in /etc/shadow — maximum password age, warning days, inactivity lock, and account expiry. Use it to enforce rotation policy or set temporary accounts without editing shadow by. |
| Related guides | Linux commands |
chage — quick reference
View aging
| When to use | Command |
|---|---|
| Show all password and account aging fields | sudo chage -l username |
| List dates in ISO8601 (YYYY-MM-DD) format | sudo chage -i -l username |
Password timing
| When to use | Command |
|---|---|
Set maximum password age in days (-1 = never) |
sudo chage -M DAYS username |
| Set minimum days between password changes | sudo chage -m DAYS username |
| Days before expiry to warn the user | sudo chage -W DAYS username |
| Set last password change date | sudo chage -d YYYY-MM-DD username |
| Force password change at next login | sudo chage -d 0 username |
| Remove maximum age (password never expires) | sudo chage -M -1 username |
Account lock and expiry
| When to use | Command |
|---|---|
| Lock account N days after password expires (inactivity) | sudo chage -I DAYS username |
| Disable inactivity lock | sudo chage -I -1 username |
| Set calendar account expiry date | sudo chage -E YYYY-MM-DD username |
| Remove account expiry | sudo chage -E -1 username |
Disable account immediately (-E 0) |
sudo chage -E 0 username |
Interactive and chroot
| When to use | Command |
|---|---|
| Prompt for each aging field interactively | sudo chage username |
| Operate on accounts under a chroot | sudo chage -R /mnt/sysroot -l username |
| Prefix path for etc/shadow location | sudo chage -P /mnt/etc -l username |
Help
| When to use | Command |
|---|---|
| Show built-in usage | chage -hchage --help |
chage — command syntax
Synopsis from chage --help on Ubuntu 25.04 (chage from passwd 1:4.16.0-7ubuntu1):
Usage: chage [options] LOGIN
Options:
-d, --lastday LAST_DAY set date of last password change to LAST_DAY
-E, --expiredate EXPIRE_DATE set account expiration date to EXPIRE_DATE
-i, --iso8601 use YYYY-MM-DD when printing dates
-I, --inactive INACTIVE set password inactive after expiration to INACTIVE
-l, --list show account aging information
-m, --mindays MIN_DAYS set minimum number of days before password change to MIN_DAYS
-M, --maxdays MAX_DAYS set maximum number of days before password change to MAX_DAYS
-R, --root CHROOT_DIR directory to chroot into
-P, --prefix PREFIX_DIR directory prefix
-W, --warndays WARN_DAYS set expiration warning days to WARN_DAYSchage edits aging columns in /etc/shadow (fields 3–8). It does not change the password hash — use passwd for that.
chage — command examples
Essential List current aging with chage -l
Start here before changing policy — you see last change, expiry, inactivity, and account expiration in one place.
Run the command:
sudo useradd -m cschage_demo
sudo chage -l cschage_demoSample output:
Last password change : Jul 01, 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 : 7Clean up at the end of your test:
sudo userdel -r cschage_demoEssential Set max age, min age, warning, and inactivity
Typical corporate rotation: 90-day passwords, 7-day minimum between changes, warn 7 days early, lock 10 days after expiry if not changed.
Run the command:
sudo useradd -m cschage_demo
sudo chage -M 90 cschage_demo
sudo chage -m 7 cschage_demo
sudo chage -W 7 cschage_demo
sudo chage -I 10 cschage_demo
sudo chage -l cschage_demoSample output (dates shift with your test day):
Maximum number of days between password change : 90
Minimum number of days between password change : 7
Number of days of warning before password expires : 7
Password inactive : 10sudo userdel -r cschage_demoEssential Force password change at next login (-d 0)
Sets last-change to the epoch — the password is treated as expired immediately. The account is not locked; login continues after a new password is set.
Run the command:
sudo useradd -m cschage_demo
sudo chage -d 0 cschage_demo
sudo chage -l cschage_demo | head -5Sample output:
Last password change : password must be changed
Password expires : password must be changedCommon after resets or onboarding.
sudo userdel -r cschage_demoCommon Password never expires (-M -1)
Service accounts often use no password rotation — set max age to -1.
Run the command:
sudo useradd -m cschage_demo
sudo chage -M -1 cschage_demo
sudo chage -l cschage_demo | grep -i 'password expires'Sample output:
Password expires : -1A value of -1 means no maximum — some builds print never instead; both mean the same policy.
sudo userdel -r cschage_demoCommon Set and clear account expiry date (-E)
Contractors and temp accounts get a calendar account expires date — login stops after that day.
Run the command:
sudo useradd -m cschage_demo
sudo chage -E 2026-12-31 cschage_demo
sudo chage -l cschage_demo | grep -i 'account expires'
sudo chage -E -1 cschage_demo
sudo chage -l cschage_demo | grep -i 'account expires'Sample output:
Account expires : Dec 31, 2026
Account expires : never-E 0 disables the account immediately.
sudo userdel -r cschage_demoCommon Set last password change date (-d)
Adjust when the password was last changed — defer or bring forward expiry without running passwd.
Run the command:
sudo useradd -m cschage_demo
sudo chage -M 90 cschage_demo
sudo chage -d 2026-01-15 cschage_demo
sudo chage -l cschage_demo | grep -i 'last password'Sample output:
Last password change : Jan 15, 2026Dates accept YYYY-MM-DD or days since 1970-01-01 per the man page.
sudo userdel -r cschage_demoAdvanced ISO8601 dates in listings (-i)
When scripts parse chage -l, -i prints ISO dates instead of locale-style month names.
Run the command:
sudo useradd -m cschage_demo
sudo chage -E 2026-12-31 cschage_demo
sudo chage -i -l cschage_demo | grep -i 'account expires'Sample output:
Account expires : 2026-12-31Note: -i when listing is ISO8601 output; -I (capital) sets inactive days — different option.
sudo userdel -r cschage_demoAdvanced Interactive chage session
Running chage with only a username prompts for each field. Press Enter to keep the value shown in brackets.
Run the command (non-interactive capture is not practical here). On a test user:
sudo useradd -m cschage_demo
sudo chage cschage_demoYou see prompts such as:
Changing the aging information for cschage_demo
Enter the new value, or press ENTER for the default
Minimum Password Age [0]:
Maximum Password Age [99999]:Press Enter through prompts to leave defaults, then verify:
sudo chage -l cschage_demo
sudo userdel -r cschage_demoInteractive mode suits one-off admin work; scripts use -M, -m, -W, and -E flags.
chage — when to use / when not
| Use chage when | Use something else when |
|---|---|
|
chage vs passwd
| chage | passwd | |
|---|---|---|
| Changes | Aging fields in shadow | Password hash |
| Expiry policy | Yes | No |
| Interactive password | No | Yes |
Run passwd to set a new password; run chage to control when it must change again.
chage — interview corner
What does chage do?
chage (change age) reads and writes password aging fields in /etc/shadow: last change date, min/max password age, warning period, inactivity lock, and account expiry. It does not change the encrypted password itself.
A strong answer is:
"chage manages shadow aging — expiry, warnings, inactivity, account date — not the password hash."
Which /etc/shadow fields does chage control?
Fields 3–8: lastchg, min, max, warn, inactive, expire. Field 2 (password hash) is untouched. Dates are stored as days since 1970-01-01 internally; CLI accepts YYYY-MM-DD for many options.
A strong answer is:
"chage edits shadow fields 3–8 — last change, min/max age, warn, inactive, expire — not the hash."
How do you force a user to change password at next login?
sudo chage -d 0 username — last password change moves to the epoch so the password is expired immediately. Login succeeds only after they set a new password (unless other locks apply).
A strong answer is:
"chage -d 0 — expired password flag; user must set a new password on next login."
What is the difference between password inactive and account expires?
-I (inactive) — days after password expiry before the account locks if the user never changed an expired password. -E (expire) — calendar date when the account is disabled regardless of password state.
A strong answer is:
"Inactive is grace after password expiry; account expires is a hard calendar cutoff for the whole account."
Who can run chage?
Only root or sudo. Regular users cannot change aging fields for themselves (some distros let users run chage -l on their own account — check policy).
A strong answer is:
"chage needs root/sudo to modify aging; it's an admin policy tool."
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
user 'x' does not exist |
Typo or missing account | getent passwd x; create user first |
invalid date |
Bad -d or -E format |
Use YYYY-MM-DD |
| User not prompted to change password | PAM or -M -1 |
chage -l; check LOGIN_DEFS |
| Account locked unexpectedly | Inactivity (-I) after expiry |
chage -l; extend or chage -I -1 |
Confused -i vs -I |
Similar letters | -i ISO listing; -I inactive days |
chage -l date off by one day |
Timezone vs epoch storage | Trust the flag value; compare with chage -i -l (ISO dates) |
| Changes missing in chroot | Wrong system root | chage -R /path/to/chroot |
