Configure Account Lockout in 389 Directory Server

Enable password-based account lockout in 389 Directory Server, set failure thresholds and unlock behaviour, inspect lockout attributes, test automatic unlock, recover locked accounts, and replicate lockout state.

Published

Updated

Read time 14 min read

Reviewed byDeepak Prasad

389 Directory Server account lockout with failed bind counter, accountUnlockTime, and LDAPS verification on a test user

Repeated wrong passwords are one of the fastest ways to compromise LDAP accounts. Password-based account lockout counts failed simple binds, stores the state in operational attributes on the user entry, and rejects further authentication until the lockout expires or an administrator clears it.

This guide covers:

  • Enabling lockout and setting thresholds and unlock behaviour
  • Understanding n versus n+1 timing with passwordLegacyPolicy
  • Inspecting lockout attributes and testing automatic unlock and counter reset
  • Manual recovery, local-policy overrides, and replicating lockout operational state

Password complexity, expiration, and hashing belong in password policy and password storage schemes. Manual disabling and inactivity policies belong in disable user accounts.

Before you start:

IMPORTANT
This guide covers failed-password lockout only. It does not cover manual account disabling with nsAccountLock, inactivity-based disabling, password expiration, grace logins, or temporary-password rules. Those topics have dedicated chapters linked above.

Tested on: Rocky Linux 10.2; 389 Directory Server 3.2.0.

Lockout tests use instance ldap2 on ldap2.example.com with suffix dc=lab,dc=example,dc=com, LDAP port 1389, and LDAPS port 1636. That keeps the exercise away from other password-policy work on ldap1 in the same lab. The test user is uid=lockout-test,ou=people,dc=lab,dc=example,dc=com.


Record the baseline before you change policy

I'll save the current global policy and legacy setting before enabling lockout for the lab:

bash
dsconf ldap2 pwpolicy get > /root/ldap2-pwpolicy-before-lockout.txt

I'll record the legacy threshold setting separately because it controls whether lockout triggers on the nth or n+1th failed attempt:

bash
dsconf ldap2 config get passwordLegacyPolicy > /root/ldap2-legacy-policy-before-lockout.txt

Restore the values you recorded at the end of the exercise. Do not assume the defaults on your instance match another host.


How password-based account lockout works

When account lockout is enabled, each failed simple bind increments a counter on the user entry. After the configured threshold is reached or exceeded, Directory Server locks the account and rejects further binds until automatic unlock time passes or an administrator clears the operational state.

Password lockout flow from failed bind through retry counter and account lock to automatic unlock or administrative recovery

The figure is a decision path, not a timing diagram. Whether lock state triggers on the nth or n+1th failed attempt depends on passwordLegacyPolicy, and the bind that crosses the threshold may still return invalid credentials (49) before later binds return constraint violation (19). The recovery branch on the right applies when --pwdunlock off or an administrator clears operational attributes before the timer expires.

Directory Server stores the state in operational attributes on the user entry:

Attribute Purpose
passwordRetryCount Number of failed bind attempts
retryCountResetTime Time after which the failed-attempt count can reset
accountUnlockTime Time when a locked account becomes usable again

A successful bind after the reset window clears passwordRetryCount. While the account is locked, even the correct password is rejected.


Distinguish account lockout from other account states

Feature Trigger
Password account lockout Repeated failed password binds
Manual account disabling Administrator locks the account
Account inactivity User has not logged in for a configured period
Password expiration Password exceeds its maximum age

Manual disabling and inactivity-based policies are covered in disable user accounts. dsidm account lock and dsidm account unlock manage manual nsAccountLock state; they are not the same workflow as password-policy lockout recovery.


Check the current account lockout policy

Read the global password policy on the Directory Server host:

bash
dsconf ldap2 pwpolicy get

Sample output on the tested host before lockout was enabled for the exercise:

output
passwordlockout: off
passwordunlock: on
passwordlockoutduration: 3600
passwordmaxfailure: 3
passwordresetfailurecount: 600

Filter the lockout-related lines when you only need those settings:

bash
dsconf ldap2 pwpolicy get | grep -Ei 'lockout|maxfailure|resetfailure|unlock|pwdisglobal'

I'll read the legacy threshold setting separately because it changes when lockout state is triggered:

bash
dsconf ldap2 config get passwordLegacyPolicy

Sample output:

output
passwordLegacyPolicy: on

dsconf ldap2 pwpolicy get shows the global policy only. To see which policy applies to a specific user, inspect local policies with dsconf ldap2 localpwp get "USER_DN" when nsslapd-pwpolicy-local is enabled.


Configure the global account lockout policy

I'll enable lockout with short lab-friendly durations so you can reproduce the tests quickly:

bash
dsconf ldap2 pwpolicy set --pwdlockout on --pwdmaxfailures 3 --pwdresetfailcount 30 --pwdunlock on --pwdlockoutduration 30

Sample output:

output
Successfully updated global password policy

The Successfully updated global password policy line confirms the lockout settings were written to the global policy.

Option Lab value Meaning
--pwdlockout on Enables failed-bind lockout
--pwdmaxfailures 3 Failed-attempt threshold
--pwdresetfailcount 30 Reset window for the failed-attempt count in seconds
--pwdunlock on Automatically unlock locked accounts
--pwdlockoutduration 30 Keep the account locked for 30 seconds

Verify the active settings:

bash
dsconf ldap2 pwpolicy get

Sample output:

output
passwordlockout: on
passwordunlock: on
passwordlockoutduration: 30
passwordmaxfailure: 3
passwordresetfailurecount: 30

Use stricter values in production. The lab values exist only to make automatic unlock and counter-reset tests finish in under a minute.


Understand n vs n+1 lockout behaviour

Check the legacy setting before you explain the real attempt limit to operators:

bash
dsconf ldap2 config get passwordLegacyPolicy
Setting When lock state is triggered for threshold 3
passwordLegacyPolicy=on After the fourth failed password verification
passwordLegacyPolicy=off After the third failed password verification

The bind that triggers the lock can still return invalid credentials (49). A later bind against the already locked account returns constraint violation (19). Capture the complete sequence on your installed release before you document the exact response transition.

On the tested host with legacy mode enabled, attempts 1–3 returned 49, attempt 3 also stored accountUnlockTime, and attempt 4 returned 19. With legacy mode disabled, attempts 1–2 returned 49 and attempt 3 returned 19.

To demonstrate strict n behaviour temporarily:

bash
dsconf ldap2 config replace passwordLegacyPolicy=off

Run the failed-bind test sequence, then restore legacy mode before you continue with the rest of the lab:

bash
dsconf ldap2 config replace passwordLegacyPolicy=on

The restore returns the server to the n+1 lock-state behaviour used in the earlier baseline.


Alternative unlock and reset settings

The sections below change individual settings for explanation. They are not part of the linear lockout test unless you restore the lab baseline afterward.

Automatically unlock after a longer duration

Production example:

bash
dsconf ldap2 pwpolicy set --pwdunlock on --pwdlockoutduration 1800

When --pwdunlock is on, Directory Server sets accountUnlockTime and the account becomes usable again after the configured duration.

Require administrator intervention

bash
dsconf ldap2 pwpolicy set --pwdunlock off

When automatic unlock is disabled, --pwdlockoutduration is ignored and the account stays locked until an administrator clears the operational attributes or resets the password. Indefinite lockout increases the impact of intentional denial-of-service attacks against known user names.

After you review indefinite lockout, restore the automatic-unlock lab settings:

bash
dsconf ldap2 pwpolicy set --pwdunlock on --pwdlockoutduration 30 --pwdresetfailcount 30

Longer failure-counter reset window

Production example:

bash
dsconf ldap2 pwpolicy set --pwdresetfailcount 600

The failure-counter reset interval is not the same as lockout duration. The reset window only clears an unfinished sequence before the account locks.

Example progression:

text
Attempt 1 fails
Attempt 2 fails
No more attempts for longer than the reset window
Next failed attempt starts a new count at 1

The counter-reset and automatic-unlock tests later in this guide use --pwdresetfailcount 30 and --pwdlockoutduration 30 from the lab baseline.


Apply lockout to a subtree or individual user

Before you discuss a local lockout policy, inspect the fine-grained policy switches:

bash
dsconf ldap2 config get nsslapd-pwpolicy-local nsslapd-pwpolicy-inherit-global

Sample output on the tested host:

output
nsslapd-pwpolicy-local: off
nsslapd-pwpolicy-inherit-global: off

Account-lockout settings can be defined in a local password policy for a subtree or a single user when nsslapd-pwpolicy-local is on. Typical targets include ou=Contractors,ou=people,dc=lab,dc=example,dc=com or uid=service1,ou=ServiceAccounts,dc=lab,dc=example,dc=com.

Inspect an existing local policy:

bash
dsconf ldap2 localpwp get "uid=user1,ou=people,dc=lab,dc=example,dc=com"

Set lockout options on a local policy when one already exists:

bash
dsconf ldap2 localpwp set "POLICY_DN" --pwdlockout on --pwdmaxfailures 5 --pwdresetfailcount 300

Local policies override the global policy for the entry or subtree to which they apply. Global password-syntax settings can be inherited when nsslapd-pwpolicy-inherit-global is enabled, but do not assume every lockout setting is merged automatically. Configure and verify the lockout threshold, reset interval, unlock behaviour, and duration explicitly in each local policy.

Creation, precedence, and removal of local policies belong in password policy.


Test failed login lockout

I'll create a disposable test user and store both the valid and invalid test passwords in protected files:

bash
install -m 600 /dev/null /root/lockout-test.pw

I'll create a second protected file for the deliberately wrong password used in failed-bind tests:

bash
install -m 600 /dev/null /root/lockout-test-bad.pw

Populate the files through an editor or another approved local secret-entry method. The lab uses uid=lockout-test,ou=people,dc=lab,dc=example,dc=com.

Point LDAP clients at the issuing CA before you connect over LDAPS:

bash
export LDAPTLS_CACERT=/root/ldap2-ca-chain.pem

Attempt a failed bind over LDAPS:

bash
ldapwhoami -x -H ldaps://ldap2.example.com:1636 -D "uid=lockout-test,ou=people,dc=lab,dc=example,dc=com" -y /root/lockout-test-bad.pw

Sample output on the first failed attempt:

output
ldap_bind: Invalid credentials (49)

Repeat until the account locks. With passwordLegacyPolicy=on and --pwdmaxfailures 3, attempts 1–3 returned 49 and attempt 4 returned:

output
ldap_bind: Constraint violation (19)
	additional info: Exceed password retry limit. Please try later.

Then bind with the correct password from the protected file:

bash
ldapwhoami -x -H ldaps://ldap2.example.com:1636 -D "uid=lockout-test,ou=people,dc=lab,dc=example,dc=com" -y /root/lockout-test.pw

Sample output while the account remains locked:

output
ldap_bind: Constraint violation (19)
	additional info: Exceed password retry limit. Please try later.

Do not run lockout tests against production users or application service accounts. Simple-bind credentials must not be transmitted over unencrypted LDAP.


Inspect the account lockout attributes

Request the operational attributes explicitly as Directory Manager over LDAPS with ldapsearch:

bash
ldapsearch -LLL -o ldif-wrap=no -x -H ldaps://ldap2.example.com:1636 -D "cn=Directory Manager" -y /root/ldap2-dm.pw -b "uid=lockout-test,ou=people,dc=lab,dc=example,dc=com" -s base passwordRetryCount retryCountResetTime accountUnlockTime

Sample output after the third failed bind with legacy mode enabled, before the fourth bind:

output
dn: uid=lockout-test,ou=people,dc=lab,dc=example,dc=com
passwordRetryCount: 3
retryCountResetTime: 20260716071047Z
accountUnlockTime: 20260716071048Z

passwordRetryCount appears after the first failed bind. retryCountResetTime appears once failed authentication begins. accountUnlockTime appears when the account enters the locked state, which can occur on the same attempt that still returns 49 when legacy mode is enabled.

Correlate the same attempts in the access log:

text
/var/log/dirsrv/slapd-ldap2/access

Look for repeated bind results with result code 49 followed by result code 19 when the account locks.


Verify automatic unlocking and counter reset

Confirm the lab baseline from the previous section is still active before you run these checks.

For automatic unlock:

  1. Lock the test account.
  2. Confirm that the correct password is rejected with constraint violation (19).
  3. Wait until accountUnlockTime passes.
  4. Bind with the correct password again over LDAPS.
  5. Confirm successful authentication.
  6. Inspect the lockout attributes again.

On the tested host, a locked test account bound successfully again after waiting 32 seconds with --pwdlockoutduration 30.

For failure-counter reset:

  1. Clear the operational attributes and perform two failed binds.
  2. Wait longer than --pwdresetfailcount.
  3. Attempt another invalid bind.
  4. Confirm that passwordRetryCount starts a new sequence.

On the tested host, two failed binds left passwordRetryCount: 2. After a 32-second pause, the next failed bind stored passwordRetryCount: 1.


Recover a locked account manually

Password-policy lockout is separate from manual nsAccountLock state. On the tested release, dsidm ldap2 account unlock reported Account is already active while passwordRetryCount and accountUnlockTime remained on the entry and binds still failed.

Use this tested administrative recovery workflow:

  1. Confirm the account is locked because of password retries rather than manual inactivation.
  2. Search the entry and note which lockout attributes are present.
  3. Build a delete modification that includes only those attributes.
  4. Submit the modification as Directory Manager over LDAPS.
  5. Search again and verify removal.
  6. Test the correct password from the protected file.

Search the entry first:

bash
ldapsearch -LLL -o ldif-wrap=no -x -H ldaps://ldap2.example.com:1636 -D "cn=Directory Manager" -y /root/ldap2-dm.pw -b "uid=lockout-test,ou=people,dc=lab,dc=example,dc=com" -s base passwordRetryCount retryCountResetTime accountUnlockTime

Include only attributes shown by the preceding ldapsearch. Do not blindly delete all three attributes when one or more are absent. The upstream recovery procedure identifies passwordRetryCount and accountUnlockTime as the primary lockout attributes to clear.

When all three attributes are present on the entry, clear them with ldapmodify over LDAPS:

bash
ldapmodify -x -H ldaps://ldap2.example.com:1636 -D "cn=Directory Manager" -y /root/ldap2-dm.pw <<'EOF'
dn: uid=lockout-test,ou=people,dc=lab,dc=example,dc=com
changetype: modify
delete: passwordRetryCount
-
delete: retryCountResetTime
-
delete: accountUnlockTime
EOF

After the attributes are removed, the test user bound successfully again on the tested host.

Do not use dsidm account unlock as the primary recovery path for password-policy lockout unless you verify that behaviour on your exact Directory Server version.


Configure account lockout in a replication topology

Directory Server evaluates lockout on every server, but passwordRetryCount, retryCountResetTime, and accountUnlockTime are not replicated by default. Without synchronization, a user can continue failed attempts against another replica.

Run this on each supplier to allow password-policy operational state such as retry counters and unlock time to replicate:

bash
dsconf ldap2 pwpolicy set --pwdisglobal on

That setting does not replicate the configuration under cn=config.

Every authentication server must separately use compatible values for:

  • passwordLockout
  • passwordMaxFailure
  • passwordResetFailureCount
  • passwordUnlock
  • passwordLockoutDuration
  • passwordLegacyPolicy
  • nsslapd-pwpolicy-local
  • Applicable local policy entries and inheritance settings

Compare policy on each supplier before you test cross-replica lockout:

bash
dsconf supplier1 pwpolicy get

I'll read the global password policy on the second supplier so I can confirm the lockout thresholds match:

bash
dsconf supplier2 pwpolicy get

The legacy setting must also match on every supplier, or the same failed-attempt count can lock on one server and not another:

bash
dsconf supplier1 config get passwordLegacyPolicy

Read the same legacy setting on the second supplier:

bash
dsconf supplier2 config get passwordLegacyPolicy

Enable --pwdisglobal on on every supplier, then review fractional replication exclusions on each agreement:

bash
dsconf ldap2 repl-agmt get --suffix "dc=lab,dc=example,dc=com" AGREEMENT_NAME | grep nsDS5ReplicatedAttributeList

Ensure the three lockout attributes are not excluded.

Replication is asynchronous. Enabling lockout-attribute replication improves consistency but does not create an instantaneous, centralized rate limiter. Concurrent attempts sent rapidly to different suppliers can occur before replicated counters converge.

Test in a real multi-supplier topology through the actual load-balancer path:

  1. Fail a bind against supplier 1.
  2. Read passwordRetryCount on supplier 1.
  3. Read the same attribute on supplier 2.
  4. Confirm that the values converge.
  5. Complete the remaining failed attempts through different servers.
  6. Confirm that the account is locked consistently.

The lab host used for this guide did not have a replication agreement configured for dc=lab,dc=example,dc=com, so those steps were not executed here.


Monitor and audit account lockouts

Review:

text
/var/log/dirsrv/slapd-ldap2/access
/var/log/dirsrv/slapd-ldap2/errors
/var/log/dirsrv/slapd-ldap2/security

The security log is intended for security and authentication-related events and is enabled by default in current RHDS releases. Access-log writes may be buffered, so an event might not appear in the access log immediately. Use the security log and the systemd journal through journalctl when you need a quicker view:

bash
journalctl -u dirsrv@ldap2 --since "10 minutes ago"

Monitor for:

  • Repeated invalid credentials (49)
  • Constraint-violation lockout responses (19)
  • Frequently locked users
  • Service accounts repeatedly submitting old passwords
  • Attempts distributed across several replicas
  • Unexpected automatic-unlock failures

Avoid logging clear-text passwords in scripts or test commands.


Troubleshoot account lockout problems

Symptom Likely cause Fix
Account locks after one more attempt than expected passwordLegacyPolicy=on Document n+1 lock-state timing or set passwordLegacyPolicy=off
First LDAP 19 appears later than expected Lock state and denial response are separate events Capture the full 49/19 sequence on your release
passwordRetryCount does not increase Lockout disabled, wrong effective policy, or bind did not reach this server Confirm --pwdlockout on, check global versus local policy, and retest on the inspected replica
Correct password still fails Account is locked Inspect accountUnlockTime, wait for automatic unlock, or clear the operational attributes
Account never unlocks automatically --pwdunlock off or clock skew Confirm passwordunlock: on, review --pwdlockoutduration, and verify server time
Counter resets sooner or later than expected Wrong --pwdresetfailcount or time sync issue Review the configured window and compare retryCountResetTime with the server clock
Account locks on one replica but works on another Lockout attributes not replicated or policy mismatch Align policy on every supplier, enable --pwdisglobal on, and review fractional replication exclusions
Service account repeatedly locks Application still using an old password Fix the application credentials before raising the failure threshold
Account is inactive but has no retry-count attributes Manual disable or Account Policy inactivity Use disable user accounts troubleshooting, not password-lockout recovery

Account lockout security recommendations

  • Use a threshold that slows guessing without making denial-of-service attacks trivial.
  • Prefer temporary lockout for ordinary users.
  • Monitor permanent lockout configurations closely.
  • Document whether your deployment uses n or n+1 lock-state timing.
  • Keep short reset and lockout durations in test environments only.
  • Configure consistent lockout policy on every authentication server and replicate operational lockout attributes.
  • Exclude trusted monitoring probes from password-based health checks when they would consume failure counters.
  • Test with disposable users, not Directory Manager.
  • Investigate repeated service-account failures instead of continuously clearing lockout state.

Summary

  1. Enable account lockout with --pwdlockout on.
  2. Set the failure threshold and counter-reset interval.
  3. Choose temporary or indefinite lockout with --pwdunlock.
  4. Verify passwordLegacyPolicy to understand when lock state is triggered.
  5. Inspect passwordRetryCount, retryCountResetTime, and accountUnlockTime.
  6. Test failed binds, automatic unlock, and conditional ldapmodify recovery over LDAPS.
  7. Configure consistent lockout policy on every authentication server, replicate the operational lockout attributes, and test convergence through the actual load-balancer path.

What's Next


References


Frequently Asked Questions

1. What is the default account lockout setting in 389 Directory Server?

Lockout is disabled by default on a new instance. Common defaults when lockout is enabled are three maximum failures, a 600-second failure-count reset window, a 3600-second lockout duration, and automatic unlocking enabled. dsconf INSTANCE pwpolicy get shows the global policy only; check localpwp get for the effective policy on a specific user.

2. Does --pwdmaxfailures 3 always return LDAP error 19 on the third wrong password?

No. passwordLegacyPolicy controls when lock state is triggered. With legacy mode on, lock state is triggered after the fourth failed verification when the threshold is 3. With legacy mode off, it is triggered after the third. The bind that triggers the lock can still return invalid credentials (49); a later bind against the already locked account returns constraint violation (19).

3. How do I unlock a user locked by the password policy?

Delete the lockout operational attributes present on the entry, usually passwordRetryCount and accountUnlockTime, or wait for accountUnlockTime when automatic unlock is enabled. Build the ldapmodify delete list from a preceding ldapsearch. dsidm account unlock clears manual nsAccountLock state but does not remove password-policy lockout attributes on the tested release.

4. Are lockout counters replicated between Directory Server instances?

Not by default. --pwdisglobal on allows password-policy operational state such as retry counters and unlock time to replicate. It does not replicate cn=config policy settings. Configure compatible lockout policy on every supplier, enable --pwdisglobal on all of them, and confirm fractional replication does not exclude the lockout attributes.

5. What LDAP error appears when an account is locked?

Failed attempts before lock state is triggered usually return invalid credentials (49). After the account is locked, binds return constraint violation (19), often with Exceed password retry limit in the additional info text. Capture the full sequence on your installed release because the transition can occur on the attempt after lock state is set.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …