Limit password attempts in Linux It's not just a quirk of paranoid administrators; it's one of the most effective measures to stop brute-force attacks and unauthorized access, both in desktop and server environments. If your computer contains sensitive information or connects to the internet, you'll want to secure this part of the system. audit your local network.
In addition to setting a strong password, configure temporary or permanent locks after several failures This is key: it slows down attackers, generates more logs for auditing, and allows you to combine this protection with other password policies (expiration, complexity, reuse, etc.). Let's look, calmly but in detail, at how this is done in different distributions and at different levels of the system.
Account lockout due to failed login attempts on Red Hat, CentOS, and derivatives
In the distributions based on Red Hat (RHEL, CentOS, Rocky, AlmaLinux…)Account blocking due to failed attempts is managed with the PAM module pam_faillockThis module controls how many failed login attempts are allowed, how long the account is locked, and which users are affected (including, if you wish, the root user).
To apply this policy, you need to edit the global PAM files, normally /etc/pam.d/system-auth and, in some versions, also /etc/pam.d/password-authThese files act as templates for most authentication services on the system (console login, sudo, SSH, etc.).
These files contain lines similar to these, within the section of auth y account:
auth required pam_faillock.so preauth silent audit deny=2 unlock_time=120
auth pam_faillock.so authfail audit deny=2 unlock_time=120
account required pam_faillock.so
The first line of action before real authentication (preauth)The second one runs when authentication fails, and the third one is responsible for checking the account's lock status during the phase of accountBy modifying the parameters, you can adjust the policy to your needs.
The most common parameters of pam_faillock are:
- audit: Enables detailed logging of login attempts, so that traces are left in the system logs (for example, in / var / log / secure).
- deny=2This sets the maximum number of failed password attempts before the account is locked. In this example it's 2, but you can increase it (3, 5, 10…).
- unlock_time=120: indicates the blocking time in seconds. Here it would be 120 seconds (2 minutes) until the account is automatically reactivated.
- silentIf it is present, It does not show the user that they have been blockedIt simply stops accepting logins, making the system less "verbose" to an attacker.
One important detail is that, by default, root is excluded from this blockIf you want the same rules to apply to it as well, you need to add the parameter even_deny_root in the pam_faillock lines of the auth section. This strengthens security, but you should weigh the risk of losing access if you make too many mistakes.
When an account is locked and you don't use the parameter silentThe system can display explicit messages warning that the user has exceeded the allowed number of attempts. This is useful in test environments to verify the configuration, although in production it's usually best not to provide too much information.
To view a specific user's failed login attempts, on Red Hat systems you can use the command faillock pointing to the account you're interested in:
faillock --user lionel
This command shows How many failed attempts has the user accumulated?, including the IP address used in the case of SSH and other details relevant to the audit. Additionally, you can always review what appears in / var / log / securewhere these security events will be recorded.

Account lockout due to failed login attempts in Debian and Ubuntu
In the case of Debian, Ubuntu and derivativesThe logic is similar, but the PAM module used changes. Traditionally, it has been used pam_tally2 to count failed attempts and automatically block accounts, although in modern versions it is recommended to migrate to pam_faillockEven so, pam_tally2 is still very present in many guides and environments.
To apply a lock based on the number of failed attempts in typical Debian, you usually edit the file /etc/pam.d/common-authwhich defines the standard authentication policy for most local services. You can add a line like this to it:
auth required pam_tally2.so onerr=fail deny=3 unlock_time=120 audit even_deny_root root_unlock_time=600
With this configuration, the system The account is blocked after 3 failed attempts.It maintains the lock for 120 seconds for normal users and for 600 seconds for root. Furthermore, if any error occurs with the module (onerr=fail), for security reasons access is denied instead of allowed.
The main parameters of pam_tally2 are:
- onerr=failIf there is a problem reading or updating the attempt counter, authentication is denied to avoid accidentally leaving a door open.
- deny=3: Maximum number of failed attempts allowed before the account is locked. A value of 3 is usually quite reasonable in practice.
- unlock_time=120: time in seconds that the account will remain locked for standard users.
- audit: logs authentication failure information (in Debian, it is usually /var/log/auth.log).
- even_deny_root: forces root to also be counted in this locking system, something that should be used with caution.
- root_unlock_time=600: specific lock time for the root account, in seconds, independent of the other users.
When the block is activated, the user will see a message indicating that their account has been temporarily disabled due to too many failed login attempts. This allows the administrator to detect suspicious behavior and alerts the user that something is wrong.
To view the failed attempts recorded by pam_tally2 For a specific user (for example, lionel), you can use:
pam_tally2 -u lionel
This command shows the number of accumulated failures And it allows you to manually reset the counter if needed, with additional options. Furthermore, just like in Red Hat, you always have the option to review /var/log/auth.log to see in more detail what happened in each authentication attempt.
Limit SSH attempts with MaxAuthTries
One of the most common entry points in Linux servers is SSHThat's why it's critical to control how many authentication attempts are allowed per connection. This is where the policy comes into play. MaxAuthTries, which is configured in the file / Etc / ssh / sshd_config from the OpenSSH server.
The idea is simple: MaxAuthTries defines the maximum number of authentication attempts allowed per SSH connectionIf this limit is exceeded, the server cuts off the connection, forcing the attacker to start a new session to continue trying combinations, which significantly slows down automated brute-force attacks.
To configure it, simply edit the configuration file:
sudo nano /etc/ssh/sshd_config
Next, locate or add a line like this:
MaxAuthTries 3
With this value, Only three authentication attempts are allowed per SSH connectionIf the user makes the same mistake multiple times, the sshd daemon logs them out. For the change to take effect, the service must be reloaded or restarted, for example with:
sudo systemctl restart sshd
MaxAuthTries does not replace PAM modules such as pam_tally2 or pam_faillock, but rather works in parallelThe SSH server controls how many consecutive attempts are allowed in a single session, while PAM keeps a global count per user and can block their account at the system level.
In addition to MaxAuthTries, it's advisable to combine other SSH security measures to make the service much more robust:
- Change the default port: Stop using port 22 and move SSH to a less obvious port helps filter out many basic automatic scans.
- Use public keys instead of just passwordsAuthentication using SSH keys eliminates the problem of weak passwords and is much more robust against brute-force attacks.
- Restrict sources using a firewall or configure a DMZAllowing SSH only from specific IP addresses or network ranges adds a very effective barrier at the network level.
Limit local authentication attempts with PAM
Beyond SSH, the local authentication (console, TTYs, sudo, graphical display manager) is also managed with PAM. In Debian and Ubuntu, for example, the file /etc/pam.d/common-auth It is the heart of this configuration, and in Red Hat systems its role is played system-auth (and sometimes password-auth).
In addition to dedicated blocking modules like pam_faillock or pam_tally2, some distributions allow limiting login attempts and times directly through login.defsIn this file, located in /etc/login.defsValues such as the following are declared:
- LOGIN_RETRIES: maximum number of retries allowed at the login prompt before aborting the process.
- LOGIN_TIMEOUT: maximum time, in seconds, that the login session is allowed to remain waiting for user input.
For example, if you adjust LOGIN_RETRIES With a 3-password limit, a user will only have three attempts to enter their password in a single login session before the system closes that attempt, forcing them to restart the process. It doesn't lock the account per se, but it does limits attempts per session.
In the same file login.defs You can also adjust other relevant security parameters, such as:
- PASS_MAX_DAYS: maximum number of days a password can be used before it is forced to be changed.
- PASS_MIN_DAYS: minimum number of days between password changes, to avoid excessively frequent and "chain" changes.
- PASS_WARN_AGE: days of notice before the password expires, so that the user has time to react.
- PASS_MIN_LEN y PASS_MAX_LEN: minimum and maximum password length.
- PASS_ALWAYS_WARN: warns when the password does not meet certain strength criteria.
- PASS_CHANGE_TRIES: maximum number of password change attempts if the new password is considered too simple.
- ENCRYPT_METHOD: hash algorithm to use for passwords (the usual thing today is SHA-512, indicated as $ $ 6).
These directives primarily affect new users These are created after adjusting login.defs, so it's a convenient way to establish a baseline policy for the entire organization.
Managing attempts and expiration with /etc/shadow and the change command
The file / Etc / shadow This is where the system stores the encrypted passwords of local users, along with all expiration information. Although they are not changed manually on a daily basis, understanding their structure greatly helps in auditing and refining security policies.
In each line of / Etc / shadow Several fields appear, separated by colons. The most relevant to our policies are:
- Username: identifies the account to which the rest of the fields belong.
- Encrypted password: is stored as $id$salt$hashedWhere $id$ indicates the algorithm ($1 MD5, $2a$/$2y$ Blowfish, $5 SHA-256, $6 SHA-512), followed by salt and hash.
- Last password change: number of days since January 1, 1970 (epoch) when it was last modified.
- Minimum and maximum days of useThey control when the password can be changed again and when it expires.
- Expiration notice days: how many days before expiration does it start notifying the user.
- Days of inactivityOnce the password has expired, how long does it take before the account is completely disabled?
- Absolute account expiration date: also in days format since 1970, marks the moment when login is no longer allowed for that user.
To manage these parameters without directly touching /etc/shadow, the following command is used: change (change age), which allows you to adjust the password and account expiration for specific users.
Some common options for change are:
- -d, –lastday: sets the day of the last password change (in days since epoch format or with a readable date).
- -E, –expiredate: sets the date from which the account expires.
- -I, –inactive: marks the account as inactive after a number of days from the password expiry.
- -m, –mindays: defines the minimum number of days between password changes.
- -M, –maxdays: indicates the maximum number of days for which the password remains valid.
- -W, –warndays: sets how many days before expiry it will start notifying.
- -l, –list: shows the current expiration status of a user.
For example, to check the user's expiration information pepper It can be executed:
chage -l pepe
The exit will indicate the date of the last change, whether the password expires or not, inactivity, and the minimum and maximum days...among other data. With this tool you can apply policies individually, user by user, or in scripts that process entire groups of accounts.
Password complexity policies with pam_cracklib and pam_pwquality
Limiting password attempts is great, but if the passwords are something like “123456” or “qwerty”, you're not going to get very far. That's why it's crucial. force strong passwords using PAM modules such as pam_cracklib and, in more recent versions, pam_pwquality.
The pam_pwquality It is an evolution of cracklib, and it integrates with libraries such as libpwquality to verify that passwords are not in dictionaries, are not too short, and do not repeat simple patterns or the user's personal data. It is included natively in RHEL-based environments and can be installed in Debian/Ubuntu using packages such as libpam-cracklib y libpam-pwquality.
Once installed, the main configuration is usually done in the file /etc/security/pwquality.confwhere you can define complexity parameters such as:
- difok: number of characters that must be different from the previous password.
- minlen: minimum acceptable length for the new password.
- dcredit, ucredit, credit, creditCredits for including digits, uppercase letters, lowercase letters, and other characters.
- min class: minimum number of different character classes required (lowercase, uppercase, digits, symbols).
- max repeat: maximum number of consecutive identical characters allowed.
- maxclassrepeat: maximum number of consecutive characters of the same class.
- gecoscheck: checks that the password does not contain words from the GECOS (comment) field of the user in /etc/passwd.
- dictpath: path to the dictionary used to check if a password is part of a known word.
- badwords: list of words that are explicitly banned.
The system credits It's especially flexible. Basically, a password gains credits for including a variety of characters; those credits can compensate for a slightly shorter length. For example, with minlen=10 y dcredit=2An 8-character password with 2 digits could pass the filter because it adds 2 extra credits. However, if you define negative credits, you require at least one negative character (for example, dcredit=-1 (requires at least one digit, no exceptions).
With min class You can require the password to include several different classes. A value of 2 forces, for example, a combination of letters and numbers, or letters and symbols, etc. minclass=4 It would require the use of lowercase letters, uppercase letters, digits, and special characters simultaneously, something very typical in demanding corporate policies.
Tools like pwscore They allow you to test the strength of a password against defined policies. When a password is passed through pwscoreThis tells you whether the key meets the requirements or not and, if not, which rule it is violating (insufficient length, too simple, too similar to the previous one, etc.).
Configure robust policies on Debian and Ubuntu with pam_cracklib
In Debian/Ubuntu systems it is very common to use pam_cracklib (or pwquality via PAM) to enforce the password policy. The key file here is /etc/pam.d/common-password, which defines how password changes are managed for system users.
Before touching anything, it's good practice to make a backup copy of the file:
sudo cp /etc/pam.d/common-password /root/
Then you can edit it with your favorite text editor (nano, vim, etc.) with superuser privileges. Inside you'll find a line similar to:
password requisite pam_cracklib.so retry=3 minlen=8 difok=3
Here, parameters such as the following are defined:
- retry: number of attempts allowed to the user when changing their password, before the change fails.
- minlen: minimum password length.
- difok: number of characters that must be different from the previous password.
- ucredit, credit, dcredit, credit: positive or negative credits for uppercase letters, lowercase letters, digits, and other characters.
For example, a fairly demanding policy might be:
password requisite pam_cracklib.so retry=3 minlen=12 difok=3 ucredit=-3 lcredit=-3 dcredit=-3 ocredit=-3
With this setup, Every new password must be at least 12 characters longThe password must differ by at least 3 characters from the previous one and contain at least 3 uppercase letters, 3 lowercase letters, 3 digits, and 3 symbols. It's a very strict policy, but extremely effective against trivial passwords.
Once you've changed the policy, you can test it by changing your own password with:
sudo passwd
If the password doesn't meet the requirements, the system will display messages indicating the reason: too short, similar to a dictionary word, excessive repetition of characters, etc. Once the password complies with the policy, the change will be applied without issue.
In addition to tightening the policy for new changes, Debian and Ubuntu allow force existing users to change their password to adapt to the new rules. With the command:
passwd -e USUARIO
That user's password is marked as expired, and on their next login, they will be required to set a new password that complies with the current policy. You can also control global password expiration with:
passwd -w 5 -x 30 USUARIO
where -x 30 establishes a maximum validity of 30 days for the password and -in 5 This makes the system start notifying you 5 days before the expiration date. If you add -i 1:
passwd -w 5 -x 30 -i 1 USUARIO
The account will be marked as inactive if the user does not change their password. one day after it has expired, forcing the administrator to intervene to reactivate it.
Although rotating passwords frequently has been recommended for years, modern security guidelines (such as those from NIST) qualify this practice: It is preferable to opt for long and complex passwords, and for two-factor authentication systems, rather than forcing overly frequent changes that end up generating predictable keys.
Carefully configure the PAM modules (pam_faillock, pam_tally2, pam_cracklib, pam_pwquality), and key files such as /etc/pam.d/common-auth, /etc/pam.d/common-password, /etc/login.defs, / Etc / ssh / sshd_config and understand how those decisions are reflected in / Etc / shadowThis marks the difference between a "standard" system and a truly hardened environment against unauthorized access and brute-force attacks.
