Limiting how many times an account can fail to authenticate before being blocked is a core hardening control on Linux servers. Account lockout policies reduce the window for brute‑force password guessing on services like SSH, console login, and remote administration tools, especially when hosts are reachable from untrusted networks.
Linux distributions implement this control through Pluggable Authentication Modules (PAM) using the pam_faillock module and the /etc/security/faillock.conf configuration file. pam_faillock tracks failed authentication attempts per user in a tally directory and denies access once a configurable threshold of consecutive failures is reached, integrating with the auth and account phases of the PAM stack.
Incorrect PAM ordering or thresholds that are too strict can lock legitimate users out of critical systems, including administrative accounts, so configuration changes must be applied cautiously and tested on non‑privileged users first. On Ubuntu and Debian, enabling pam_faillock in /etc/pam.d/common-auth and /etc/pam.d/common-account applies the policy to most login paths, while values in /etc/security/faillock.conf tune how aggressively failures are counted and how long accounts remain locked.
Steps to automatically lock accounts after failed login attempts:
- Open a terminal on the server with an account that can use sudo.
$ whoami user
- Open a second privileged shell or console session for recovery before changing PAM configuration.
$ sudo -i whoami root
Misordered PAM entries can block all interactive logins, so a spare root session is essential for restoring backups if authentication fails.
- Create backups of the existing /etc/pam.d/common-auth and /etc/pam.d/common-account files.
$ sudo cp /etc/pam.d/common-auth /etc/pam.d/common-auth.backup $ sudo cp /etc/pam.d/common-account /etc/pam.d/common-account.backup
Backups allow quick rollback by copying the saved files back into place from the recovery shell if logins stop working.
- Open or create the /etc/security/faillock.conf policy file.
$ printf '%s\n' '# /etc/security/faillock.conf' 'deny = 5' 'fail_interval = 900' 'unlock_time = 600' | sudo tee /etc/security/faillock.conf # /etc/security/faillock.conf deny = 5 fail_interval = 900 unlock_time = 600
/etc/security/faillock.conf is the preferred location for pam_faillock options on modern Linux systems.
- Define a lockout policy such as five failed attempts within fifteen minutes and a ten‑minute lockout period.
# /etc/security/faillock.conf deny = 5 fail_interval = 900 unlock_time = 600
deny is the number of consecutive failures allowed, fail_interval is the window in seconds in which those failures are counted, and unlock_time is the lock duration in seconds.
- Update the /etc/pam.d/common-auth file with the pam_faillock entries in the Primary block, then confirm the updated block.
$ sudo sed -n '1,30p' /etc/pam.d/common-auth # # /etc/pam.d/common-auth - authentication settings common to all services # # This file is included from other service-specific PAM config files, # and should contain a list of the authentication modules that define # the central authentication scheme for use on the system # (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the # traditional Unix authentication mechanisms. # # As of pam 1.0.1-6, this file is managed by pam-auth-update by default. # To take advantage of this, it is recommended that you configure any # local modules either before or after the default block, and use # pam-auth-update to manage selection of other modules. See # pam-auth-update(8) for details. # here are the per-package modules (the "Primary" block) auth required pam_faillock.so preauth auth [success=3 default=ignore] pam_unix.so nullok auth [default=die] pam_faillock.so authfail # here's the fallback if no module succeeds auth requisite pam_deny.so # prime the stack with a positive return value if there isn't one already; # this avoids us returning an error just because nothing sets a success code # since the modules above will each just jump around auth required pam_permit.so auth sufficient pam_faillock.so authsucc # and here are more per-package modules (the "Additional" block) auth optional pam_cap.so # end of pam-auth-update config
Only change the auth block for local password authentication and leave distribution‑managed comments and include statements intact to avoid breaking other authentication methods.
- Update the /etc/pam.d/common-account file to include a pam_faillock account entry, then confirm the Primary block.
$ sudo sed -n '1,30p' /etc/pam.d/common-account # # /etc/pam.d/common-account - authorization settings common to all services # # This file is included from other service-specific PAM config files, # and should contain a list of the authorization modules that define # the central access policy for use on the system. The default is to # only deny service to users whose accounts are expired in /etc/shadow. # # As of pam 1.0.1-6, this file is managed by pam-auth-update by default. # To take advantage of this, it is recommended that you configure any # local modules either before or after the default block, and use # pam-auth-update to manage selection of other modules. See # pam-auth-update(8) for details. # # here are the per-package modules (the "Primary" block) account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so # here's the fallback if no module succeeds account requisite pam_deny.so # prime the stack with a positive return value if there isn't one already; # this avoids us returning an error just because nothing sets a success code # since the modules above will each just jump around account required pam_permit.so account required pam_faillock.so # and here are more per-package modules (the "Additional" block) # end of pam-auth-update config
Using the required control flag ensures that account evaluation fails when the tally indicates the user is locked.
Keep the backup file until the configuration has been validated across all login paths used on the system.
- Reset any existing failure tally for the test account before validating the lockout.
$ sudo faillock --user audituser --reset
- From a separate session, generate several failed logins for a non‑privileged test account to trigger the lockout threshold.
$ for attempt in $(seq 1 5); do sshpass -p "badpass" ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no -o StrictHostKeyChecking=accept-new audituser@localhost; done Pseudo-terminal will not be allocated because stdin is not a terminal. Permission denied, please try again. Pseudo-terminal will not be allocated because stdin is not a terminal. Permission denied, please try again. Pseudo-terminal will not be allocated because stdin is not a terminal. Permission denied, please try again. Pseudo-terminal will not be allocated because stdin is not a terminal. Permission denied, please try again. Pseudo-terminal will not be allocated because stdin is not a terminal. Permission denied, please try again.
Using a dedicated test account avoids unintentionally locking an administrator out of the system during validation.
- Inspect the failure tally for the test account with faillock to confirm the account is locked after the configured number of attempts.
$ sudo faillock --user audituser audituser: When Type Source Valid 2026-01-13 01:11:06 RHOST ::1 V 2026-01-13 01:11:09 RHOST ::1 V 2026-01-13 01:11:13 RHOST ::1 V 2026-01-13 01:11:17 RHOST ::1 V 2026-01-13 01:11:20 RHOST ::1 V
faillock reads per‑user tally files from the failure directory and shows recent invalid attempts that contribute to the lockout state.
- Reset the tally for the test account to unlock it and verify that the entry disappears.
$ sudo faillock --user audituser --reset $ sudo faillock --user audituser audituser: When Type Source Valid
Use the reset command to clear the failure count after investigating suspicious activity so that legitimate users can log in again.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
