chage

When a password expires, and when the account does

Updated 2026-10-02

chage reads and sets the dates in /etc/shadow: when the password was last changed, how long it may be kept, how much warning comes before it expires, how long after that the account can still log in to change it, and a date on which the whole account stops working. chage -l prints those settings worked out into dates, which is the easiest way to find out why a login is being refused.

Every limit except the account's own expiry is counted from the last change, so setting a maximum age on a password that is already old can expire it immediately. The account's expiry date is fixed, and it is separate from the password: an expired account cannot log in by any route, where an expired or locked password only stops the password itself. Root can change any account's settings, and an ordinary user can read their own.

Sample files used on this page

Every example below was run against these files. Recreate them to follow along.

the accounts The same two accounts as managing-users, id and passwd, rebuilt before every example. Both have a locked password and the package's default ageing, and each one's last password change is pinned to 1 September 2026, so every date chage works out is the same on every run.

tips-dev:x:1001:1001:Deployment account:/home/tips-dev:/bin/bash
tips-ops:x:1002:1002:Operations account:/home/tips-ops:/bin/bash
tips-dev L 2026-09-01 0 99999 7 -1
tips-ops L 2026-09-01 0 99999 7 -1
15 outputs, collapsed by default

Reading the settings

Read an account's ageing settings

chage -l tips-dev

The first four lines are dates, worked out from the numbers in the last three. A maximum of 99999 days, about 273 years, is the package default and means the password never expires.

Show output
Last password change					: Sep 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	: 7

Print the dates in ISO form

chage -l -i tips-dev | head -3

-i prints YYYY-MM-DD, which sorts correctly and reads the same in every locale, so it is the form to use when a script is going to compare it.

Show output
Last password change					: 2026-09-01
Password expires					: never
Password inactive					: never

Read where the settings are stored

chage -M 90 -I 14 -E 2027-03-31 tips-dev; getent shadow tips-dev | cut -d: -f3-8

Fields 3 to 8 of the account's line in /etc/shadow: the last change, the minimum and maximum age, the warning, the inactivity period and the account's expiry. The two dates are days since 1 January 1970, so 20697 is 1 September 2026. An empty field means no limit.

Show output
20697:0:90:7:14:20908

Read your own settings as an ordinary user

runuser -u tips-dev -- chage -l tips-dev | head -2

chage -l works for the account running it, so anyone can find out when their own password expires. Changing the settings needs root.

Show output
Last password change					: Sep 01, 2026
Password expires					: never

Try to read another account's settings

runuser -u tips-dev -- chage -l tips-ops

Refused, with no details about why. The dates are in /etc/shadow, which only root and the shadow group can read.

Show output
chage: Permission denied.

Expiring passwords

Each setting below is counted in days from the last password change, which here is 1 September 2026.

Make passwords expire after 90 days

chage -M 90 tips-dev; chage -l tips-dev | head -2

-M is the maximum age. Ninety days from 1 September is 30 November, and after that the next login has to choose a new password before it gets a shell.

Show output
Last password change					: Sep 01, 2026
Password expires					: Nov 30, 2026

Warn people before their password expires

chage -M 90 -W 14 tips-dev; chage -l tips-dev | tail -1

-W is how many days before expiry a login starts printing a warning. Seven is the default.

Show output
Number of days of warning before password expires	: 14

Disable an account left unchanged after expiry

chage -M 90 -I 14 tips-dev; chage -l tips-dev | sed -n 2,3p

-I is the inactivity period. Up to 14 days after the password expires, a login can still change it. After that the account is disabled, and only root can get it working again.

Show output
Password expires					: Nov 30, 2026
Password inactive					: Dec 14, 2026

Stop a password being changed straight back

chage -m 7 tips-dev; chage -l tips-dev | grep Minimum

-m is the minimum age: once a password has been changed, its owner cannot change it again for that many days. With a password history policy, it stops someone changing their password several times in a minute to get back to the old one. Root is not held to it.

Show output
Minimum number of days between password change		: 7

Force a new password at the next login

chage -d 0 tips-dev; chage -l tips-dev | head -3

-d sets the date of the last change, and 0 is 1 January 1970, so the password counts as expired. It is the same as passwd -e, and the usual step after setting a temporary password for someone.

Show output
Last password change					: password must be changed
Password expires					: password must be changed
Password inactive					: password must be changed

Record a password change made somewhere else

chage -d 2026-09-15 tips-dev; chage -l tips-dev | head -1

-d with a date sets the last change to that day, without touching the password itself. Useful when accounts are copied between machines and their ageing would otherwise restart from the day of the copy.

Show output
Last password change					: Sep 15, 2026

Expiring the account

An account's expiry date is a fixed day, unrelated to when the password was changed. Once it has passed, the account cannot log in by any route, a key or a password, which is what makes it the right control for a temporary account.

Expire the account on a particular date

chage -E 2027-03-31 tips-dev; chage -l tips-dev | grep 'Account expires'

The account works until the end of 30 March and stops on the 31st. passwd shows an expired account being refused by SSH even with a working key.

Show output
Account expires						: Mar 31, 2027

Give the date as a number of days

chage -E 20818 tips-dev; chage -l tips-dev | grep 'Account expires'

-E and -d both take a number of days since 1 January 1970 as well as a date, which is the form /etc/shadow stores and the form a script working out a date with arithmetic will have.

Show output
Account expires						: Dec 31, 2026

Remove an account's expiry date

chage -E 2027-03-31 tips-dev; chage -E -1 tips-dev; chage -l tips-dev | grep 'Account expires'

-1 clears the field, so the account never expires. -I -1 clears the inactivity period the same way.

Show output
Account expires						: never

Beside passwd -l

Lock a password without changing its ageing

chage -M 90 tips-dev; passwd -l tips-dev; chage -l tips-dev | sed -n 2p

A lock and an expiry are separate. passwd -l only puts a ! in front of the stored password, and leaves every date where it was, so unlocking the password later finds the same expiry still waiting.

Show output
passwd: password changed.
Password expires					: Nov 30, 2026