— LiveStream

To create a functional ID without an expiring date in AIX, set the account expiration to 0 and the password maximum age to 0 with a single chuser command, then disable interactive remote login so the account behaves like a service account. This guide walks through the exact attributes that matter, the command-line and SMIT methods, the common mistakes that silently lock these accounts, and how to verify the configuration so the ID never gets disabled by a password-aging or account-expiry policy.
What a functional ID is and why it expires
A functional ID (also called a service account, application account, or non-personal account) is a UNIX user that an application, batch job, or middleware product such as DB2, WebSphere, or a backup agent runs under. It is not tied to a human, so nobody is around to respond when AIX prompts that a password is about to expire.
On AIX the security database enforces two separate clocks that are easy to confuse, and both can disable a functional ID in AIX if left at their defaults:
- Account expiration — the
expiresattribute in/etc/security/user. A non-zero value is a calendar date after which the whole account is dead. SMIT shows this as EXPIRATION date (MMDDhhmmyy). - Password maximum age — the
maxageattribute, measured in weeks. After this many weeks the password must be changed or the account locks on the next login.
For a true non-expiring account you must zero out both. A value of 0 means "no limit" for each. Many admins set only maxage=0, then are surprised months later when the account still expired — because the expires date was the real culprit.
The solution: zero both clocks and harden remote login
The cleanest way to set up a functional ID without an expiring date is the chuser command. It edits the AIX security stanzas safely instead of you hand-editing files. Run it as root:
- Decide the username (the service ID), for example
db2inst1orappsvc. Replace<userid>below with that name. - Apply all the non-expiry attributes in one pass:
chuser account_locked='false' login='true' rlogin='false' expires='0' maxage='0' minage='0' maxexpired='-1' <userid> - If the ID does not exist yet, create it first, then apply the same attributes:
mkuser pgrp='staff' home='/home/<userid>' shell='/usr/bin/ksh' <userid>chuser login='true' rlogin='false' expires='0' maxage='0' minage='0' maxexpired='-1' <userid> - Set an initial password and clear the forced-change flag so the unattended ID is not asked to change it on first use:
passwd <userid>pwdadm -c <userid>
The pwdadm -c step is critical for service accounts: a freshly set password normally carries an ADMCHG flag that forces a password change at first login. An application that logs in non-interactively cannot answer that prompt, so it fails. Clearing the flag prevents that.
What each attribute does
| Attribute | Value | Effect |
expires | 0 | Account never expires (no calendar end date). |
maxage | 0 | Password never expires (no maximum age in weeks). |
minage | 0 | No minimum wait before the password can be changed. |
maxexpired | -1 | Password is usable indefinitely even past expiry (belt-and-suspenders for legacy policies). |
login | true | Local console/su login allowed (needed for su and cron). |
rlogin | false | Blocks direct remote login (telnet/rlogin/ssh) — people must su in. |
account_locked | false | Account is not administratively locked. |
Note: the original quick-and-dirty form sometimes seen in the field, chuser login='true' rlogin='false' maxage='0' userid, only handles the password clock. It leaves expires untouched, so if anyone ever stamped an expiration date on the ID it will still die. The fuller command above is the correct, complete recipe.
Method 1: command line with chuser (preferred)
The command line is repeatable and scriptable, which is why it is the right choice for a functional ID in AIX that you may rebuild across many LPARs. After running the chuser command, confirm the change in one line:
lsuser -a expires maxage minage rlogin login account_locked <userid>
Expected output looks like:
appsvc expires=0 maxage=0 minage=0 rlogin=false login=true account_locked=false
Every clock attribute should read 0 (or -1 for maxexpired). If any shows a non-zero number, that attribute is still enforcing expiry.
Tightening security without breaking the ID
Because the account never expires, compensate elsewhere so it does not become an audit finding:
- Keep
rlogin=falseso the ID cannot be used to log straight in over the network — force named admins tosu - <userid>, which creates an audit trail. - Restrict who may
suto it with thesugroupsattribute, e.g.chuser sugroups='dba,sysadmin' <userid>. Avoid the wide-opensu=truefor ALL groups that the SMIT default suggests. - If the app uses key-based or token authentication only, consider
chuser login='false'as well so no password login is possible at all (cron andsustill work for system-launched processes in most setups — test in your environment).
Method 2: the SMIT / smitty screen
If you prefer the menu-driven tool, AIX's smitty writes the same attributes for you. This is handy when you want to see every field on one screen.
- As
root, launch the user fastpath:smitty chuser(orsmitty userthen Change / Show Characteristics of a User). - Type the functional ID name and press Enter.
- On the Change / Show Characteristics of a User panel, set these fields:
- EXPIRATION date (MMDDhhmmyy) →
0 - Password MAX. AGE →
0 - Password MIN. AGE →
0 - Is this user ACCOUNT LOCKED? →
false - User can LOGIN? →
true - User can LOGIN REMOTELY (rsh,tn,rlogin)? →
false
- EXPIRATION date (MMDDhhmmyy) →
- Press Enter to commit. SMIT runs the underlying
chuserand reports OK. - Press F10 (or Esc+0) to exit, then verify with
lsuseras shown above.
The fields map one-to-one to the command-line attributes: EXPIRATION date is expires, Password MAX. AGE is maxage, and so on. SMIT simply enters 0 for you where the CLI expects 0.
Where AIX stores these settings
Understanding the underlying files helps you troubleshoot and audit a functional ID without an expiring date. AIX never wants you to edit these by hand — use chuser — but knowing where the truth lives is invaluable:
/etc/security/user— holds the per-user stanza withexpires,maxage,minage,rlogin,login, andsugroups. Adefault:stanza at the top sets system-wide defaults that a new ID inherits./etc/security/passwd— holds the encrypted password and theflagsline.flags = ADMCHGis the forced-change marker thatpwdadm -cclears./etc/security/lastlog— recordsunsuccessful_login_count; if this hits theloginretrieslimit the account locks even though it never "expired"./etc/passwd— the classic file with UID, GID, home, and shell.
Common pitfalls
These are the issues that make a supposedly permanent account stop working:
- Setting only
maxage=0. Ifexpiresstill holds a date, the account dies on that date regardless of password settings. Always zero both. - Leaving the
ADMCHGflag. The first non-interactive login fails with a forced password change you cannot answer. Runpwdadm -c <userid>after setting the password. - Account lock from failed logins. The
loginretriesattribute (the SMIT "Number of FAILED LOGINS before user account is locked" field, default 5) locks the ID after repeated bad attempts. A misconfigured app retrying a wrong password will trip it. Unlock withchuser account_locked='false' <userid>and reset the counter withchsec -f /etc/security/lastlog -s <userid> -a unsuccessful_login_count=0. - Inherited
default:stanza values. A new ID inheritsmaxageandexpiresfrom thedefault:stanza in/etc/security/user. If the system default enforces aging, you must override it explicitly per user withchuser. - Editing the files by hand. Hand-edits can corrupt stanzas. Use
chuser/chsecso AIX keeps the database consistent. - Compliance scanners flag the ID. Security tools often flag accounts with
maxage=0. Document the exception, restrictsuviasugroups, and rotate the password manually on a schedule even though it is not forced.
Verification: confirm the functional ID never expires
Do not assume the change worked — prove it. Run these checks after configuration:
- Dump the relevant attributes:
lsuser -a expires maxage minage maxexpired rlogin login account_locked loginretries <userid> - Confirm the account is not currently locked and the password is not flagged for change:
lsuser -a account_locked <userid>pwdadm -q <userid>The
pwdadm -qoutput should not showADMCHG. - Test a real login path the application will use. To validate
suaccess from an admin account:su - <userid> -c 'id; echo login-ok'A clean
login-okwith the correct UID confirms the ID is usable. - Check the failed-login counter is zero so a stale lock is not lurking:
lssec -f /etc/security/lastlog -s <userid> -a unsuccessful_login_count
When every clock attribute reads 0 (or -1 for maxexpired), the account is unlocked, and su succeeds, the functional ID in AIX is correctly set up to never expire.
Key Takeaways
- Zero both clocks: set
expires=0(account) andmaxage=0(password) — doing only one leaves the ID able to expire. - Use
chuseron the command line for repeatable builds, orsmitty chuserfor a guided screen; both write the same AIX security stanzas. - Run
pwdadm -cafter setting the password so theADMCHGforced-change flag does not break unattended logins. - Harden the never-expiring ID with
rlogin=falseand a restrictedsugroupslist to keep an audit trail and satisfy security reviews. - Verify with
lsuser -aand a realsu -test — never assume; watch out for failed-login lockouts and inherited default-stanza aging.
Frequently Asked Questions
What is the difference between expires and maxage in AIX?
expires is a calendar date after which the entire account stops working, shown in SMIT as the EXPIRATION date in MMDDhhmmyy format. maxage is the password maximum age in weeks, after which the password must be changed. A value of 0 disables each limit. For a non-expiring functional ID you must set both to 0.
How do I check if an AIX account or password has expired?
Run lsuser -a expires maxage account_locked <userid> to see the configured limits and lock state, and pwdadm -q <userid> to inspect the password flags. If account_locked=true or the flags show ADMCHG, the ID will fail to log in even if expiry is set to 0.
Why does my AIX service account still lock even with maxage=0?
The most common causes are an unrelated expires date that was never zeroed, a forced-change ADMCHG flag from a fresh password, or the failed-login counter hitting loginretries. Fix them with chuser expires='0' account_locked='false' <userid>, pwdadm -c <userid>, and resetting unsuccessful_login_count to 0.
Should a functional ID allow remote login in AIX?
Best practice is rlogin=false so the shared service ID cannot be used to log in directly over the network. Administrators instead su - <userid> from their own named accounts, which preserves accountability. Pair this with a restricted sugroups value to limit who can switch to the ID.
For more AIX and UNIX system administration walkthroughs, subscribe to our YouTube channel @explorenystream.