Inspect and Set faillog Login Failure Limits Safely
You will use faillog to inspect failed-login records, set a per-account failure limit, and reset counters without accidentally applying a policy to every account. The examples match shadow-utils 4.13, supplied here by Ubuntu's login package version 1:4.13+dfsg1-4ubuntu3.2. Allow about fifteen minutes, including a second check after any change.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide needs a shell and the login package. Reading records is normally an ordinary user action, but changing /var/log/faillog requires elevated privileges. Have a maintenance window if you are changing a production login policy. The file uses fixed-length records indexed by numeric UID, and it is the local failure log, not a replacement for your authentication service's audit trail.
1. Check the installed command and database
Start with read-only checks. The installed command does not accept --version, so use the package database to identify the implementation and ask the command for its supported options:
$ command -v faillog
/usr/sbin/faillog
$ dpkg-query -W -f='${Package} ${Version}\n' login
login 1:4.13+dfsg1-4ubuntu3.2
$ faillog --help
Usage: faillog [options]
The manual identifies this release family as shadow-utils 4.13. Confirm that the backing file exists before treating an empty display as evidence that no records are available:
$ sudo test -e /var/log/faillog && echo 'faillog database exists'
faillog database exists
The sudo is only needed here if your account cannot inspect the file metadata. Do not edit the binary file directly. Its records include the failure count, maximum, last terminal line, timestamp, and lock duration.
2. Inspect the records for one account
Run faillog with a named account or numeric UID. This is the least surprising way to begin because it shows an account even when a successful login would otherwise hide its old failure record:
$ faillog --user root
Login Failures Maximum Latest On
root 0 0 01/01/70 01:00:00 +0100
Your timestamp and counters will differ. The columns are the login name, current failures, maximum failures before disablement, latest failure time, and lock status or duration as displayed by this build. A zero maximum means no limit on failed logins. It does not mean that the account is locked.
Checkpoint: if you need a particular UID rather than a login name, the same query accepts a number:
$ faillog --user 0
Without --user, the command normally prints only users whose last failure has not been followed by a successful login. That default often makes a quiet system look as if it has no history. Use --all when you need existing users with empty records included:
$ faillog --all
Login Failures Maximum Latest On
root 0 0 01/01/70 01:00:00 +0100
The exact list is host-specific. The --time DAYS option filters displayed records to failures more recent than the supplied number of days. It changes what is shown, not what is stored.
3. Set a limit for one non-root account
Choose the account and number deliberately. The following sets a maximum of five failures for operator and a 300-second lock after each failed login. Both options write the database, so use sudo and confirm that the account name is correct before pressing Enter:
$ sudo faillog --user operator --maximum 5 --lock-secs 300
There is normally no success message. Verify the stored values with a read-only query:
$ faillog --user operator
Login Failures Maximum Latest On
operator 0 5 01/01/70 01:00:00 +0100
The setting is a faillog record, not a complete account policy. PAM configuration and the authentication method still control whether this database is consulted. Test the policy through your normal authentication test process, and do not deliberately generate failures against a shared or remote account.
Do not set a finite maximum for root. The installed manual explicitly recommends a maximum of zero for root to prevent an attacker from denying service by exhausting the root account's permitted attempts. This is a security boundary, not a harmless demonstration value.
4. Apply a policy to a UID range only when intended
The --user argument accepts a login, numeric UID, or range such as 1000-1099, -1099, or 1000-. Combined with --maximum, --lock-secs, or --reset, a range changes every matching record. Review the range first with a display-only command:
$ faillog --user 1000-1099
Only continue if that output contains exactly the accounts you intend to affect. Then make the change explicitly:
$ sudo faillog --user 1000-1099 --maximum 5 --lock-secs 300
With --all, the manual says display mode remains restricted to existing users, but write options can also change records for users that no longer exist. That can be useful for preparing a policy or cleaning deleted UIDs, but it is a reason to avoid combining --all with a write option unless you have reviewed the target carefully.
5. Reset counters as a separate change
--reset clears login-failure counters for the selected accounts. It is a write operation and can remove evidence useful during an incident, so record the current output first. Reset one account rather than the whole database:
$ faillog --user operator
$ sudo faillog --user operator --reset
$ faillog --user operator
Login Failures Maximum Latest On
operator 0 5 01/01/70 01:00:00 +0100
The maximum and lock duration remain policy fields; reset is for the failure counter. If you reset the wrong account, there is no general undo command in faillog. Reapply the intended limit with --maximum and --lock-secs, but do not claim that the old counter or timestamp can be reconstructed from this tool.
6. Diagnose the common traps
A permission error on --maximum, --lock-secs, or --reset means the process cannot write /var/log/faillog. Retry with sudo only after checking the target account and arguments. If the file is absent or the output is unexpectedly empty, check the file path and the local authentication stack instead of creating a replacement binary file by hand.
If a record does not appear in an unqualified listing, query it with --user or use --all. If an account appears with a zero maximum, that is the documented unlimited setting, not a failed update. If the record changes but login behaviour does not, inspect the PAM modules and their configuration: faillog stores counters and limits, while another component must enforce them.
The --root CHROOT_DIR option applies changes inside an absolute-path chroot and reads configuration files there. Treat it as an administrative migration tool, not a shortcut for the live host. Verify the directory is the intended root before using it, and do not point it at an untrusted tree.
Done means
- The installed
faillogand package version were checked. - The target account or UID range was displayed before any write.
- Any policy change used elevated privileges and was verified with a read-only query.
- The root account retains a maximum of zero unless you have a documented reason to change that protection.
- Any reset was limited to the intended account and its loss of failure history was understood.
- PAM enforcement was treated as a separate check from the contents of
/var/log/faillog.