pam_faillock: Lock User Accounts After Failed Logins on RHEL

Deepak Prasad
Tested on Red Hat Enterprise Linux 10.2 (Coughlan)
Package pam 1.6.1-9.el10
authselect 1.5.2-1.el10
Applies to RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora (authselect local profile)
Privilege root (authselect, faillock.conf, faillock reset)
Scope Enable pam_faillock with authselect on RHEL-family hosts, set deny and unlock_time in faillock.conf, verify SSH lockout, inspect tallies, and reset lockout. Does not cover Debian/Ubuntu common-auth stacks or per-user faillock exemptions.
Related guides Exclude users from faillock lockout
Unlock a locked Linux account
pam_tally2 account lockout
Prevent brute force SSH attacks
SSH command in Linux

pam_faillock counts consecutive failed authentication attempts and can temporarily lock a local account after a threshold. On RHEL, Rocky Linux, AlmaLinux, CentOS Stream, and Oracle Linux, you enable it through authselect and tune policy in /etc/security/faillock.conf — not by hand-editing /etc/pam.d/system-auth.

This guide is RHEL-family specific. Debian and Ubuntu also ship pam_faillock.so, but they stack PAM through common-auth and common-account without authselect. Mixing both layouts in one procedure confuses stack order, so keep Debian/Ubuntu lockout separate from this walkthrough.


What pam_faillock does on RHEL

pam_faillock replaces the older pam_tally2 module on current RHEL-family releases. Two pieces work together:

  • pam_faillock.so — PAM module hooks in system-auth and password-auth
  • faillock — command to inspect or reset failure records

Typical auth-stack placement:

  • preauth — checks whether the user is already locked before password verification
  • authfail — records a failure when authentication did not succeed
  • account — prevents login when the account has reached the failure limit

Failure records live under /var/run/faillock/ by default. SSH logins include password-auth, so lockout applies to remote password authentication when that stack carries pam_faillock.


Quick reference

Item Path or command
Global policy /etc/security/faillock.conf
Generated stacks /etc/pam.d/system-auth, /etc/pam.d/password-auth
Enable feature authselect enable-feature with-faillock
Disable feature authselect disable-feature with-faillock
Inspect tally faillock --user username
Clear lockout faillock --user username --reset
Failure directory /var/run/faillock/

Confirm pam_faillock is installed

The pam package on RHEL-family systems ships the module, config file, and admin command. List those paths before you change authentication:

bash
rpm -ql pam | grep faillock

Sample output:

output
/etc/security/faillock.conf
/usr/lib64/security/pam_faillock.so
/usr/sbin/faillock
/usr/share/man/man5/faillock.conf.5.gz
/usr/share/man/man8/faillock.8.gz
/usr/share/man/man8/pam_faillock.8.gz
/var/run/faillock

If pam_faillock.so is missing, install or update the pam package for your release before continuing.


Enable pam_faillock with authselect

On RHEL 8 and later, authselect owns system-auth and password-auth. Enable the built-in faillock feature instead of inserting lines by hand:

bash
authselect enable-feature with-faillock

Confirm the profile lists with-faillock:

bash
authselect current

Sample output:

output
Profile ID: local
Enabled features:
- with-faillock

When with-faillock appears under enabled features, authselect has wired pam_faillock into the managed stacks.


Set lockout policy in faillock.conf

Global limits belong in /etc/security/faillock.conf. Uncommented lines override compiled defaults. By default, pam_faillock allows three failed authentication attempts before denying further access for 600 seconds. Those defaults are:

text
deny = 3
fail_interval = 900
unlock_time = 600

You can make these values explicit in /etc/security/faillock.conf if you want them visible in the file rather than relying on compiled defaults.

To confirm active settings after you edit the file:

bash
grep -vE '^(#|$)' /etc/security/faillock.conf

Sample output:

output
deny = 3
fail_interval = 900
unlock_time = 600

Common options in that file:

  • deny — consecutive failures before lockout (default 3)
  • fail_interval — seconds in which failures must occur (default 900)
  • unlock_time — seconds until automatic unlock (0 means until manual reset)
  • even_deny_root — apply lockout to root (use with care)
  • local_users_only — track only users in /etc/passwd

Do not lock yourself out while testing over SSH. Use a disposable local user and keep a root session open.


Verify the PAM stack

SSH and many services include password-auth. Console login paths often pull in system-auth. Both stacks should reference pam_faillock:

bash
grep pam_faillock /etc/pam.d/system-auth /etc/pam.d/password-auth

Sample output:

output
/etc/pam.d/system-auth:auth        required                                     pam_faillock.so preauth silent
/etc/pam.d/system-auth:auth        required                                     pam_faillock.so authfail
/etc/pam.d/system-auth:account     required                                     pam_faillock.so
/etc/pam.d/password-auth:auth        required                                     pam_faillock.so preauth silent
/etc/pam.d/password-auth:auth        required                                     pam_faillock.so authfail
/etc/pam.d/password-auth:account     required                                     pam_faillock.so

Three lines per file — preauth, authfail, and account — mean SSH password logins can accumulate failures and enforce lockout.


Test account lockout over SSH

Use a test account so you do not risk locking your normal login:

bash
useradd -m lockdemo

Set a known password on RHEL-family hosts with passwd --stdin:

bash
echo 'LockDemoPass1!' | passwd --stdin lockdemo

Use a password you can deliberately type wrong during the SSH test — not your production credential.

Clear any old tally for that user before you start counting failures:

bash
faillock --user lockdemo --reset

faillock --reset exits silently when no records exist — that is normal.

Attempt SSH with the wrong password three times from another session (replace the password placeholder with any incorrect value):

bash
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no lockdemo@127.0.0.1

After three failed tries, list the failure records:

bash
faillock --user lockdemo

Sample output:

output
lockdemo:
When                Type  Source                                           Valid
2026-08-21 09:46:36 RHOST 127.0.0.1                                            V
2026-08-21 09:46:42 RHOST 127.0.0.1                                            V
2026-08-21 09:46:51 RHOST 127.0.0.1                                            V

Each RHOST row is one failed authentication. After three recorded failures, the account is locked. Further authentication attempts are denied until unlock_time expires or you reset the tally.

Check the system journal for the lockout message:

bash
journalctl --since '10 min ago' --no-pager | grep pam_faillock | tail -3

Sample output:

output
Aug 21 09:46:51 server.example.com sshd-session[318969]: pam_faillock(sshd:auth): Consecutive login failures for user lockdemo account temporarily locked

That line confirms pam_faillock blocked further attempts for lockdemo, not merely a wrong password on the last try.


Reset faillock and unlock the user

To let the user try again before unlock_time expires, reset the tally as root:

bash
faillock --user lockdemo --reset

Verify that the failure tally is clear:

bash
faillock --user lockdemo

Sample output:

output
lockdemo:
When                Type  Source                                           Valid

An empty table means no active failures. The user still needs the correct password — reset clears lockout state, not credentials.

When you finish testing, remove the test account:

bash
userdel -r lockdemo

pam_faillock vs pam_tally2

RHEL 7 used the older authconfig workflow; this guide targets authselect-based RHEL 8 and later.

Topic pam_faillock pam_tally2
Current RHEL Supported Not available on RHEL 8+
Configuration /etc/security/faillock.conf + authselect PAM lines and pam_tally2 command
Counter sharing Across services using the same stack Separate per-module behavior
Admin command faillock pam_tally2

For legacy tally2 setup and root lockout edge cases, see pam_tally2 account lockout. To skip lockout for named service accounts while keeping faillock for everyone else, see exclude users from pam_faillock lockout.


Troubleshooting

Symptom Likely cause Fix
Failed logins never increment the tally with-faillock not enabled Run authselect enable-feature with-faillock, then confirm with authselect current
Settings in faillock.conf ignored Options still commented with # Uncomment or append active deny / unlock_time lines
Manual edits to system-auth vanish authselect regenerated the stack Change authselect profile or faillock.conf, not /etc/pam.d/system-auth directly
Lockout persists after reset Wrong username or stale SSH session Run faillock --user exact_name --reset; confirm with faillock --user exact_name
Root is also being locked even_deny_root is enabled Remove or adjust even_deny_root, then reset the root tally with faillock --user root --reset from an existing privileged session

References


Summary

On RHEL-family Linux, account lockout after repeated bad passwords belongs to pam_faillock managed through authselect. Enable with-faillock, set deny and unlock_time in /etc/security/faillock.conf, and confirm preauth, authfail, and account lines appear in both system-auth and password-auth before you test over SSH.

faillock.conf controls when accounts are locked and automatically unlocked. The faillock command shows or clears the failed-login records for individual users. A reset clears the failed-login count; it does not change the user's password.


Frequently Asked Questions

1. Does pam_faillock work the same on Debian or Ubuntu?

The pam_faillock module exists on Debian and Ubuntu, but those distributions wire PAM through common-auth and common-account instead of authselect-managed system-auth and password-auth. Stack order and tooling differ enough that this walkthrough targets RHEL-family hosts only.

2. Should I edit /etc/pam.d/system-auth by hand?

No on RHEL 8 and later. authselect regenerates system-auth and password-auth from the selected profile. Enable with-faillock and tune /etc/security/faillock.conf, or create a custom authselect profile when you need extra PAM rules.

3. How is pam_faillock different from pam_tally2?

pam_faillock replaces pam_tally2 on RHEL 8 and later. It shares failure counters across services that include the same stack, reads defaults from faillock.conf, and ships the faillock command for inspection and reset. pam_tally2 is not available on RHEL 8 and later.

4. How do I unlock a user locked by pam_faillock?

Wait for unlock_time to expire, or run faillock --user username --reset as root. Clearing the tally does not change the password — the user still needs the correct password on the next login.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux
  • Shell Script
  • System Administration