Skip to content

AD password policy that works: length, FGPP, blocklists

Build an Active Directory password policy on NIST guidance: long passphrases, fine-grained password policies, banned and breached password checks, no rotation.

Florian Amette7 min read

Most Active Directory compromises that start with a password do not involve cracking anything clever. They start with password spraying against a policy that allows Welcome1!, with a service account whose password was set in 2014, or with a hash cracked offline because eight characters and a mandatory symbol produce a tiny search space. The default domain policy in many estates still reflects guidance from two decades ago: short passwords, complexity rules, 90-day expiry and nothing that checks whether a password is already in a breach corpus.

This guide rebuilds the policy on current evidence. It covers what NIST SP 800-63B now says, how to measure the quality of passwords you already have, how to layer fine-grained password policies for admins and service accounts, how to add banned and breached password checks at change time, and how to retire forced rotation safely.

What current guidance actually says

NIST SP 800-63B Revision 4 (finalised in 2025) is the reference most auditors accept. The points that matter for AD:

  • Length over complexity. Minimum 15 characters when a password is the only factor, 8 when it is part of MFA. Allow at least 64 characters.
  • No composition rules. Verifiers should not require mixes of character types; they push users towards predictable substitutions.
  • No periodic rotation. Change passwords only on evidence of compromise.
  • Blocklists are mandatory. Check new passwords against known-breached, dictionary and context-specific words (company name, product names).
  • Throttle online guessing rather than relying on complexity.

Microsoft's security baselines dropped password expiration in 2019 for the same reason. Your regulator or cyber insurer may still demand rotation; document the compensating controls below and negotiate from them.

Measure: what the domain enforces today

PowerShell
Get-ADDefaultDomainPasswordPolicy

Get-ADFineGrainedPasswordPolicy -Filter * |
  Select-Object Name, Precedence, MinPasswordLength, MaxPasswordAge, LockoutThreshold, AppliesTo

# Accounts that bypass the policy entirely
Get-ADUser -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=32)' | Select-Object SamAccountName   # PASSWD_NOTREQD
Get-ADUser -Filter 'PasswordNeverExpires -eq $true -and Enabled -eq $true' -Properties PasswordLastSet |
  Sort-Object PasswordLastSet | Select-Object SamAccountName, PasswordLastSet
Get-ADUser -Filter 'AllowReversiblePasswordEncryption -eq $true' | Select-Object SamAccountName

PASSWD_NOTREQD accounts can hold an empty password regardless of policy; clear the flag with Set-ADUser -PasswordNotRequired $false after confirming each one has a real password. Reversible encryption stores a recoverable password and should be zero.

Audit: the quality of existing passwords

Policy only applies at the next change, so you need to know what is already there. The DSInternals module's Test-PasswordQuality compares NT hashes against a breached-hash list (for example the Have I Been Pwned NTLM download) and reports empty, duplicate, default and weak passwords. It works by replicating hashes from a DC, which makes the run itself a Tier 0 operation: execute it from a privileged access workstation with a time-boxed replication grant, keep the output encrypted, and remove the rights afterwards. Commercial tools such as Specops Password Auditor offer the same read-only report.

Focus on three findings:

  1. Shared passwords between admin and standard accounts of the same person.
  2. Breached passwords on any privileged or service account.
  3. Duplicate hashes across service accounts, which reveal reused credentials that a single Kerberoasting crack would unlock.

Force a reset for the privileged and breached cases immediately; do not wait for the new policy.

Enforce: the domain baseline

The domain password policy is read from the GPO linked at the domain root, normally the Default Domain Policy, under Computer Configuration > Policies > Windows Settings > Security Settings > Account Policies > Password Policy. Password policy GPOs linked to OUs do not affect domain accounts.

SettingRecommended
Minimum password length14 (15+ via PSO, see below)
Password must meet complexity requirementsEnabled until a banned-password filter is live, then optional
Maximum password age0 (never) once blocklist and MFA compensate; otherwise 365 days
Enforce password history24
Minimum password age1 day
Store passwords using reversible encryptionDisabled

The Group Policy editor caps minimum length at 14. Newer Windows versions add Relax minimum password length limits and Minimum password length audit in the same node, which allow higher values; every DC and client that validates the policy must support it, so test before relying on it. PSOs never had the cap and are the simpler route to 15+.

For lockout, the Windows security baseline uses a threshold of 10 invalid attempts with 15-minute duration and reset counter. That is enough to blunt spraying without letting an attacker lock out the whole company.

Enforce: fine-grained password policies

PSOs require a domain functional level of Windows Server 2008 or higher and are stored in CN=Password Settings Container,CN=System,DC=.... Build a small, deliberate set:

PowerShell
New-ADFineGrainedPasswordPolicy -Name "PSO-AllUsers-15" -Precedence 100 `
    -MinPasswordLength 15 -ComplexityEnabled $false -PasswordHistoryCount 24 `
    -MaxPasswordAge "365.00:00:00" -MinPasswordAge "1.00:00:00" `
    -LockoutThreshold 10 -LockoutDuration "00:15:00" -LockoutObservationWindow "00:15:00" `
    -ReversibleEncryptionEnabled $false

New-ADFineGrainedPasswordPolicy -Name "PSO-Admins-20" -Precedence 10 `
    -MinPasswordLength 20 -ComplexityEnabled $false -PasswordHistoryCount 24 `
    -MaxPasswordAge "365.00:00:00" -MinPasswordAge "1.00:00:00" `
    -LockoutThreshold 10 -LockoutDuration "00:15:00" -LockoutObservationWindow "00:15:00" `
    -ReversibleEncryptionEnabled $false

New-ADFineGrainedPasswordPolicy -Name "PSO-ServiceAccounts-30" -Precedence 5 `
    -MinPasswordLength 30 -ComplexityEnabled $false -PasswordHistoryCount 24 `
    -MaxPasswordAge "365.00:00:00" -MinPasswordAge "0.00:00:00" `
    -LockoutThreshold 0 -ReversibleEncryptionEnabled $false

Add-ADFineGrainedPasswordPolicySubject "PSO-AllUsers-15"        -Subjects "PSO-Scope-AllUsers"
Add-ADFineGrainedPasswordPolicySubject "PSO-Admins-20"          -Subjects "PSO-Scope-Admins"
Add-ADFineGrainedPasswordPolicySubject "PSO-ServiceAccounts-30" -Subjects "PSO-Scope-ServiceAccounts"

Design notes:

  • PSOs apply to users and global security groups only, not OUs. Use shadow groups maintained by script if you think in OUs.
  • Lowest precedence wins; a PSO linked directly to a user beats group-linked PSOs regardless of precedence. Keep precedence values spaced out.
  • The service account PSO disables lockout because a locked service account is an outage an attacker can trigger at will; it compensates with length and should shrink as accounts move to gMSA.
  • The 365-day maximum age is an interim value. Once the compensating controls below are live, clear Enforce maximum password age on each PSO in Active Directory Administrative Center.

For privileged accounts, pair length with stronger authentication rather than more rotation: smart card or FIDO2-backed Windows Hello for Business, membership of Protected Users, and authentication policies and silos. At a Windows Server 2016 domain functional level, accounts set to Smart card is required for interactive logon can have their NTLM secret rolled automatically when msDS-ExpirePasswordsOnSmartCardOnlyAccounts is enabled on the domain.

Enforce: banned and breached password checks

A blocklist is the control that replaces complexity and rotation. Options:

  • Microsoft Entra Password Protection for AD DS. A DC agent (a password filter DLL) plus a proxy service enforce Microsoft's global banned list and your custom list on every on-premises password change. It requires Entra ID P1 or P2 licensing for on-premises enforcement and a DC reboot to install the agent. Start in Audit mode, review which changes would have been rejected, then switch to Enforce.
  • Lithnet Password Protection (open source) or commercial filters such as Specops Password Policy, which can check against a local copy of breached hashes without cloud connectivity.

Whatever you choose, it runs as a password filter inside LSASS on every DC, so treat its installation, updates and configuration store as Tier 0 change.

PowerShell
# Entra Password Protection: confirm every DC runs the agent and reports recently
Get-AzureADPasswordProtectionDCAgent | Format-Table ServerFQDN, HeartbeatUTC

Retiring forced rotation safely

Remove expiry only when these are true: the blocklist is enforcing, minimum length is 14+, MFA covers remote access and cloud apps, and you have a process to force resets on evidence of compromise (breach feeds, risky sign-in alerts, incident response). Then set Maximum password age to 0 in the domain GPO and clear Enforce maximum password age on the user and admin PSOs. Expiry is computed from pwdLastSet and the effective policy, so pending expiry warnings disappear immediately; nothing else changes.

Verify

PowerShell
# Effective policy for representative accounts
"jdoe","adm-jdoe","svc_legacyapp" | ForEach-Object {
    $pso = Get-ADUserResultantPasswordPolicy -Identity $_
    [pscustomobject]@{ User = $_; PSO = $pso.Name; MinLength = $pso.MinPasswordLength }
}

# No policy bypass flags remain
(Get-ADUser -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=32)').Count

A user with no PSO returns nothing from Get-ADUserResultantPasswordPolicy, meaning the domain policy applies. Test a change with a known-banned password such as the company name plus the year and confirm it is rejected. Re-run the password quality audit quarterly and track the number of breached and shared hashes as a metric.

What it breaks

  • Existing short passwords keep working. A longer minimum is not checked against current passwords; users are held to it only the next time they change their password. Self-service reset portals and scripted resets that generate short passwords, however, fail immediately.
  • Applications that validate passwords themselves (some VPNs, HR systems syncing passwords) may reject lengths above 14 or 16 characters.
  • Removing lockout from service accounts makes online guessing against them possible; that is acceptable only with 30+ random characters and monitoring of 4625 and 4771 failures.
  • Password filter DLLs on DCs can block all password changes if the agent fails badly; stage on one DC first and keep a rollback plan.
  • Removing rotation may conflict with a written compliance control until the policy document is updated.

Related reading: the Passwords & Service Accounts topic, the service account hardening pillar, and Kerberos hardening, where password length directly determines how long an offline attack against a service ticket takes.

Frequently asked questions

Should we stop forcing users to change their password every 90 days?

Yes, provided you replace rotation with controls that actually work: a long minimum length, a banned and breached password check at change time, MFA where possible, and forced reset when there is evidence of compromise. NIST SP 800-63B says verifiers should not require periodic changes, and Microsoft removed password expiration from its security baselines in 2019. Forced rotation mostly produces predictable patterns like Autumn2026!.

Can a fine-grained password policy be applied to an OU?

No. A password settings object applies only to user objects and global security groups. To target an OU, create a shadow group whose membership mirrors the OU, maintained by a scheduled script or your identity management tool, and link the PSO to that group. Remember that the lowest precedence number wins when several PSOs apply, and a PSO linked directly to a user overrides group-linked ones.

What minimum length should Active Directory passwords have?

NIST SP 800-63B Revision 4 sets 15 characters as the minimum for passwords used as a single authentication factor and 8 where the password is part of multi-factor authentication. For AD, 14 to 15 characters for standard users is a realistic baseline, 20 or more for administrators, and 30 or more random characters for any service account that cannot become a gMSA.

AD password policy that works: length, FGPP, blocklists

Related guides

NTLM & Legacy Protocols

Disable LLMNR, NBT-NS, mDNS and WPAD in AD

Remove the name-resolution fallbacks attackers poison: disable LLMNR, NetBIOS and mDNS by GPO and DHCP, and block WPAD with the DNS global query block list.

Foundation