Helpdesk: "Since we added DC3 on Windows Server 2025 last week, the door-badge server's directory sync fails with 'Strong Authentication Required' whenever it lands on DC3. The firewall's LDAPS test against DC2 says 'Cannot open connection' since DC2's certificate renewed, and every DC logs Event 2887 once a day. A forum post says to turn LDAP signing off in the Default Domain Controllers Policy, delete the old certificates on DC2, and set channel binding to Never. Can we start with that?"
Not yet. "LDAPS not working" and "LDAP signing required" are two different breaks that show up in the same week. LDAPS on port 636 fails when the domain controller has no certificate it can use, serves a different certificate than you think, or serves one the client doesn't trust or can't match to the name it used. Signing and channel binding failures are binds the DC now rejects on purpose. Microsoft: "There's no user interface for configuring LDAPS. Installing a valid certificate on a domain controller permits the LDAP service to listen for, and automatically accept, SSL connections for both LDAP and global catalog traffic." On signing, Microsoft's own warning: "After you make this configuration change, clients that rely on unsigned SASL (Negotiate, Kerberos, NTLM, or Digest) LDAP binds or on LDAP simple binds over a non-SSL/TLS connection stop working." Turning signing off domain-wide, deleting certificates, or setting channel binding to Never each removes evidence you need, and the first and last reopen the attacks those settings exist to stop. Work through it as a chain: which client, which DC, which port, which bind → does the DC listen on 636 and does the client reach it? → does the DC have a certificate it can use (Event 1220)? → which certificate does it actually serve? → does the client trust that certificate? → does the name the client used match it? → who is binding unsigned (Events 2887 and 2889)? → which signing policy is actually in effect on each DC? → is channel binding rejecting a TLS bind? Test-NetConnection, Get-ChildItem Cert:\LocalMachine\My, certutil, Get-WinEvent, reg query, gpresult, and ldp.exe are the sources for that chain. Turn signing off everywhere and you'll find out later which client was sending passwords in clear text.
If the DC never got a certificate because enrollment fails, Certificate Autoenrollment Not Working covers the GPO, template, and CA side. If certutil on the client fails the revocation check, Revocation Server Was Offline 0x80092013 covers CRLs and CDPs. This post covers "LDAPS on port 636 (or 3269) to a domain controller fails, an application or appliance gets 'Strong Authentication Required' after LDAP signing changes or a new Windows Server 2025 DC, or Directory Service Events 1220, 2886, 2887, 2889, 3039, or 3075 appear, and you need a read-first path before you replace certificates, restart DCs, change signing or channel binding policy, or edit NTDS registry values."
TL;DR
- LDAPS is a certificate problem first. Microsoft's requirements include: "The Enhanced Key Usage extension includes the Server Authentication (1.3.6.1.5.5.7.3.1) object identifier (also known as OID)." and the DC's FQDN in the subject CN or a SAN DNS entry (Step 3).
- The DC may not serve the certificate you're looking at. Microsoft: "If there is a certificate in the NT Directory Services (NTDS) store, DC use the certificate in the NTDS store instead." (Step 4).
- The client has to trust it. Microsoft: "The certificate was issued by a CA that the domain controller and the LDAPS clients trust." (Step 5).
- Event 2889 names the unsigned clients. Microsoft: "The log entry displays the IP address of the client and the identity that the client tried to use to authenticate." It's off until you raise a diagnostic level (Step 7).
- Windows Server 2025 changes the default. Microsoft: "Windows Server 2025 or later requires LDAP signing by default for new Active Directory deployments." (Step 8).
- Channel binding only covers TLS plus SASL. Microsoft: "LDAP channel binding applies through the Domain controller: LDAP server channel binding token requirements policy only to TLS-secured sessions that use Simple Authentication and Security Layer (SASL) authentication." (Step 9).
Where in the chain did it break?
| Step | What should be true | Typical symptom when it breaks |
|---|---|---|
| 1. Symptom captured | Which client, which DC, which port, which bind type, since when | "LDAP is broken" with no DC or port named |
| 2. Port and listener | The DC listens on 636 (and 3269 on a global catalog) and the client reaches it | TCP test fails; nothing listening |
| 3. A usable certificate | The DC holds a Server Authentication certificate with its FQDN and a private key | Event 1220 on the DC, Schannel 36886 |
| 4. The served certificate | You know which certificate the DC presents on 636 | Renewed certificate in the store, old one still served |
| 5. Client trust | The client builds a valid chain and can check revocation | Untrusted root, expired, revocation offline |
| 6. Name match | The name the client uses is in the certificate | Works by FQDN, fails by domain name, alias, or IP |
| 7. Unsigned binds | You know who binds unsigned or in clear text on 389 | Event 2887 every day, no client named |
| 8. Policy in effect | You know each DC's signing setting, including the 2025 enforcement policy | One DC rejects, the others allow |
| 9. Channel binding | You know whether TLS + SASL binds would fail CBT | Events 3039, 3074, or 3075 |
| 10. Change | Only after Steps 1-9 agree: one link, one change | Signing off everywhere, same failure |
Step 1: Capture the symptom (read-only)
Write these on the ticket first:
| Fact | Why it matters |
|---|---|
| Which client or application | A Windows computer, an appliance, a Java or Linux app, a SaaS connector. Microsoft splits devices into appliances, non-Windows devices, and Windows devices when it plans signing and channel binding |
| Which DC, and how the client finds it | A single DC FQDN, the domain name (which resolves to any DC), a load-balanced or alias name, or an IP address. The certificate has to carry the name used (Step 6) |
| Which port | 389 (LDAP), 636 (LDAPS), 3268 (global catalog), 3269 (global catalog over SSL). Microsoft: "LDAPS communication occurs over port TCP 636. LDAPS communication to a global catalog server occurs over TCP 3269." |
| Which bind type | Simple bind (a DN or user name and password) or SASL (Negotiate, Kerberos, NTLM). Signing and channel binding treat them differently (Steps 7 and 9) |
| Exact error text | "Cannot open connection" in ldp, "Strong Authentication Required", a TLS or certificate error in the app's log, or a timeout |
| Since when, and what changed | A certificate renewal, a new CA, a new DC (especially Windows Server 2025), a GPO change, a TLS hardening change, a firewall change |
Then branch on what you see:
| What you see | What it usually means (our reading unless noted) | Start at |
|---|---|---|
| Timeout on 636, or the TCP test fails | Firewall, routing, or nothing listening | Step 2 |
| Event 1220 on the DC, or "Cannot open connection" in ldp on 636 | No usable certificate. Microsoft's Event 1220 text: "LDAP over Secure Sockets Layer (SSL) will be unavailable at this time because the server was unable to obtain a certificate." | Step 3 |
| LDAPS broke right after a renewal | The DC still serves the old certificate, or picked a different one | Step 4 |
| Windows clients work, an appliance or Java app fails on 636 | The app doesn't trust your CA, or uses a name not in the certificate | Steps 5 and 6 |
| Works by DC FQDN, fails by domain name or alias | Name not in the certificate | Step 6 |
| "Strong Authentication Required" on 389 | The DC requires signing; the client sends a simple bind in clear text or an unsigned SASL bind | Steps 7 and 8 |
| Only one DC rejects binds | That DC's signing policy differs, often a new Windows Server 2025 DC | Step 8 |
| Events 3039, 3074, or 3075 | TLS + SASL binds without a valid channel binding token | Step 9 |
Step 2: Does the DC listen on 636, and does the client reach it? (read-only)
Start at the network, because nothing else matters if the handshake never starts. From the failing client, or a Windows box on the same network segment:
# Read-only. From the client side: can it open TCP 636 (and 3269 for the global catalog) on the DC it uses?
Test-NetConnection -ComputerName DC2.contoso.com -Port 636
Test-NetConnection -ComputerName DC2.contoso.com -Port 3269
On the DC itself:
# Read-only. On the DC: is anything listening on 636 and 3269?
Get-NetTCPConnection -LocalPort 636, 3269 -State Listen -ErrorAction SilentlyContinue |
Select-Object LocalAddress, LocalPort, State, OwningProcess | Format-Table -AutoSize
| Finding | What it means (our reading unless noted) | Next |
|---|---|---|
TcpTestSucceeded : False from the client, listener present on the DC |
A firewall or route between them | Fix the path; Microsoft's port reference lists LDAP SSL on TCP 636 and Global Catalog on TCP 3268 and 3269 |
| Listener present, TCP test succeeds | The port is fine; the problem is in the TLS handshake or the bind | Step 3 |
| No listener on 636 | Unusual for a DC; the LDAP service may not be running | Check the AD DS service and the Directory Service log before going further |
| 3269 fails but 636 works | The DC isn't a global catalog, or the app should use 636 | Point the app at a GC or at 636 |
A port that answers isn't the same as LDAPS working. The TCP test only proves the socket opens; a DC with no certificate still accepts the connection and then fails the TLS handshake (our reading of Microsoft's Event 1220 text and the Schannel 36886 description).
Step 3: Does the DC have a certificate it can use? (read-only)
Microsoft's requirements for an LDAPS certificate, in short: it sits in the Local Computer's Personal store, "A private key that matches the certificate is present in the Local Computer's store and is correctly associated with the certificate," the private key doesn't have strong protection, the EKU includes Server Authentication, the DC's Active Directory FQDN is the subject CN or a SAN DNS entry, and it chains to a CA both the DC and the clients trust.
First, the DC's own log. Microsoft: "Event ID 1220 is logged on a domain controller when client computers attempt to make an LDAP-over-SSL connection to the directory when SSL connections are not enabled on the directory." Schannel logs its side in the System log; Microsoft's Schannel reference describes Event 36886 as occurring "when a server attempt to make an SSL connection but no server certificate is found."
# Read-only. On the DC: Event 1220 (Directory Service) and Schannel 36886 (System), last 7 days
$since = (Get-Date).AddDays(-7)
Get-WinEvent -FilterHashtable @{ LogName = 'Directory Service'; Id = 1220; StartTime = $since } -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, Message | Format-List
Get-WinEvent -FilterHashtable @{ LogName = 'System'; ProviderName = 'Schannel'; Id = 36886; StartTime = $since } -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, Message | Format-List
Then the certificates in the computer's Personal store that could serve LDAPS:
# Read-only. On the DC: Server Authentication certificates in the computer's Personal (MY) store
Get-ChildItem -Path Cert:\LocalMachine\My -SSLServerAuthentication |
Select-Object Subject, Issuer, NotBefore, NotAfter, HasPrivateKey, Thumbprint, DnsNameList, EnhancedKeyUsageList |
Format-List
And Microsoft's validity check from the Directory Services team, which also reports the private key:
:: Read-only. On the DC: verify each certificate in the computer's Personal store (Microsoft's AskDS form)
certutil -verifystore MY
Per that post, a good certificate shows "Encryption test passed", the Server Authentication policy under "Verified Application Policies", and "Certificate is valid" at the end. The missing-key case reads "No key provider information" and "Missing stored keyset".
| Finding | What it means (Microsoft unless noted) | Next |
|---|---|---|
| No Server Authentication certificate at all | Microsoft: "If you want to configure a domain controller or an AD LDS server to support SSL connections, you must provide a certificate for the AD DS or AD LDS directory to use." | Step 10, and the autoenrollment post if enrollment fails |
HasPrivateKey is False, or "Missing stored keyset" |
AskDS: "The normal cause of this problem is that the certificate request was generated on one machine and we have installed the certificate on a different machine." | Step 10 |
NotAfter is in the past |
Expired. AskDS: "You cannot renew a certificate once it has expired." | Step 10 (new certificate) |
The FQDN isn't in Subject or DnsNameList
|
Fails the name requirement | Step 6 |
| Several valid certificates | Microsoft: "If there are multiple valid certificates available in the local computer store, Schannel may not select the correct certificate." | Step 4 |
| One good certificate, Event 1220 still logged after it was added | The DC may not have reloaded it yet (our reading) | Step 4 |
If you see no 1220 and no 36886 but LDAPS still fails, the DC probably has a certificate; the question moves to which one it serves and whether the client accepts it (our reading).
Step 4: Which certificate does the DC actually serve? (read-only)
This is where renewals go wrong. Three Microsoft statements together explain it. The NTDS store wins: "AD DS preferentially looks for certificates in this store over the Local Machine's store." In the computer store, the pick isn't predictable: "Schannel, the Microsoft SSL provider, selects the first valid certificate that it finds in the local computer store." And on newer versions: "Finally, if a Windows Server 2008 or a later version domain controller finds multiple certificates in its store, it will random chose one of these certificates." Microsoft's LDAPS troubleshooting article adds: "A conflict with a certification authority (CA) certificate may occur if the CA is installed on a domain controller that you are trying to access through LDAPS."
So read what the DC presents on the wire, not what's in the store. This asks the DC for its certificate the same way an LDAPS client would and prints it, without trusting it:
# Read-only. From the client side: which certificate does DC2 present on 636? (our form, using .NET SslStream)
# The validation callback returns $true so you can see an untrusted or wrong certificate instead of an exception
$dc = 'DC2.contoso.com'
$tcp = New-Object System.Net.Sockets.TcpClient($dc, 636)
$ssl = New-Object System.Net.Security.SslStream($tcp.GetStream(), $false, { $true })
try {
$ssl.AuthenticateAsClient($dc)
$served = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($ssl.RemoteCertificate)
$served | Select-Object Subject, Issuer, NotBefore, NotAfter, Thumbprint, DnsNameList | Format-List
# Save it for Step 5 (public certificate only)
[System.IO.File]::WriteAllBytes("$env:TEMP\dc2-ldaps.cer", $served.Export('Cert'))
} finally { $ssl.Dispose(); $tcp.Dispose() }
Change the port to 3269 to read the global catalog side. If AuthenticateAsClient throws before any certificate comes back, the DC had nothing to offer, which matches Event 1220 (our reading).
Compare the served Thumbprint with Step 3's list. Then look in the NTDS store, which the computer-store listing doesn't show. Microsoft's route is the Certificates snap-in: Service account → Local computer → Active Directory Domain Services, then NTDS\Personal. A command-line read (our form; the -service option is documented as accessing "a machine service store"):
:: Read-only. On the DC: certificates in the AD DS service's own Personal store (our form; use the MMC route if it errors)
certutil -service -store NTDS\My
| Finding | What it means (Microsoft unless noted) | Next |
|---|---|---|
| Served thumbprint = an old or expired certificate, new one in the computer store | The DC hasn't reloaded. Microsoft's older guidance: "the server must be restarted for Schannel to use the new certificate." Newer DCs can reload without a restart | Step 10 (renewServerCertificate) |
| Served certificate is in the NTDS store, not the one you renewed | The NTDS store wins | Replace it there (Step 10) |
| Served certificate is the CA's own certificate, or another Server Authentication certificate | Several candidates; the DC chose one you didn't intend | Put the intended certificate in the NTDS store (Step 10) |
| Served certificate is the one you expected | The DC side is right | Step 5 |
Step 5: Does the client trust that certificate? (read-only)
Microsoft's LDAPS troubleshooting article checks the chain from the client, with the certificate exported from the server: certutil -v -urlfetch -verify serverssl.cer > output.txt, then "Open the Output.txt file, and then search for errors." The file saved in Step 4 is the certificate the DC actually served, so use that one:
:: Read-only. On the CLIENT (or a Windows box with the same trust store): build the chain and fetch AIA and CDP URLs
certutil -v -urlfetch -verify %TEMP%\dc2-ldaps.cer > %TEMP%\dc2-ldaps-verify.txt
findstr /i "error expired revoked untrusted incomplete offline" %TEMP%\dc2-ldaps-verify.txt
-urlfetch is documented as "Retrieve and verify AIA Certs and CDP CRLs." Microsoft's AskDS post lists what the bottom of the output usually says when it fails:
certutil says |
What it means (Microsoft unless noted) | Next |
|---|---|---|
| "Expired certificate" | Past its validity period. AskDS: "Now it's possible that the system clock has been changed to an invalid date." | Check the clock first (Windows Time Not Syncing With Domain Controller), then Step 10 |
| "Verifies against UNTRUSTED root" | Per AskDS, a certificate in the chain is missing from the client's Intermediate Certification Authorities store (for an intermediate) or Trusted Root Certification Authorities store (for a root) | Step 10 (trust on the client) |
| "Incomplete certificate chain" | An intermediate certificate can't be found or fetched | Step 10 |
| "Certificate is REVOKED" | AskDS: "the certificate has been revoked and therefore a new certificate needs to be issued." | Step 10 (new certificate) |
| "Revocation check skipped" or the revocation server is offline | The client can't reach a CDP | Revocation Server Was Offline |
| Verifies clean | The chain is fine on this client | Step 6 |
Non-Windows clients (appliances, Java, Linux) don't use the Windows trust store. A clean certutil run on a Windows box proves the chain is buildable; the appliance still needs your root and intermediate imported into its own store (our reading). Microsoft's own requirement covers both sides: "Trust is established by configuring the clients and the server to trust the root CA to which the issuing CA chains."
The same server-certificate pattern (right EKU, private key present, chain the client trusts) is what breaks PEAP on NPS; NPS Event 6273 Reason Code 16 or 22 walks that version.
Step 6: Does the name the client used match the certificate? (read-only)
Microsoft's name rule: "The Active Directory fully qualified domain name of the domain controller (for example, dc01.contoso.com) must appear in one of the following places:" the subject CN or a DNS entry in the SAN. A client that connects by the domain name (contoso.com), a load-balancer or alias name (ldap.contoso.com), or an IP address checks that name instead, and a certificate issued only to DC2.contoso.com fails that check (our reading).
# Read-only. On a Windows client: does the served certificate pass SSL policy for the name the app uses?
# (Microsoft's Test-Certificate example uses -Policy SSL -DNSName 'dns=contoso.com'; the file is the one saved in Step 4)
$served = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("$env:TEMP\dc2-ldaps.cer")
$served.DnsNameList
Test-Certificate -Cert $served -Policy SSL -DNSName 'dns=DC2.contoso.com'
Test-Certificate -Cert $served -Policy SSL -DNSName 'dns=ldap.contoso.com'
Microsoft's Test-Certificate reference: "If the DNSName parameter is used, then the DNS subject alternative name is used to verify SSL policy." Then read the application's LDAP server setting and the name it uses, and check that name in DNS:
# Read-only. Where does the name the app uses resolve? (names are examples)
Resolve-DnsName -Name ldap.contoso.com -DnsOnly
Resolve-DnsName -Name contoso.com -Type A -DnsOnly
| Finding | What it means (our reading unless noted) | Next |
|---|---|---|
The app uses contoso.com
|
It reaches whichever DC DNS returns, and that DC's certificate needs contoso.com in its SAN |
Point the app at a DC FQDN, or reissue with the extra SAN (Step 10) |
| The app uses an alias or load-balancer name | That name isn't in any DC's certificate | Same choice |
| The app uses an IP address | A certificate issued to DNS names won't match an IP address | Use a name |
Test-Certificate passes for the name used |
The name isn't the problem | Step 7 if the failure is on 389, or back to Step 5 for the app's own trust store |
The Directory Services team's older post adds a caveat for multi-name certificates: "The first name in the SAN has to match the FQDN of the server." Keep the DC's own FQDN first when you reissue (our habit).
Step 7: Who is binding unsigned or in clear text? (read-only, then one low-risk logging change)
This is the 389 side. Microsoft's definition of what the DC counts, from the Event 2889 text: "The following client performed a SASL (Negotiate/Kerberos/NTLM/Digest) LDAP bind without requesting signing (integrity verification), or performed a simple bind over a clear text (non-SSL/TLS-encrypted) LDAP connection."
The DC already logs summaries without any change:
| Event | When it's logged (Microsoft) | What it tells you |
|---|---|---|
| 2886 | At startup, as a reminder when the DC doesn't require signing | This DC accepts unsigned binds |
| 2887 | "a summary Event ID 2887 one time every 24 hours to indicate how many such binds occurred" | How many, not who |
| 2888 | "a summary Event ID 2888 one time every 24 hours when such bind attempts occur" on a DC that rejects them | How many were rejected |
| 2889 | One per bind, only with the diagnostic level raised | Client IP, port, identity, and binding type |
Read the summaries on every DC first:
# Read-only. Every DC: the latest LDAP signing summaries (2886, 2887, 2888) from the Directory Service log
foreach ($dc in (Get-ADDomainController -Filter *).HostName) {
Get-WinEvent -ComputerName $dc -FilterHashtable @{ LogName = 'Directory Service'; Id = 2886, 2887, 2888 } -MaxEvents 3 -ErrorAction SilentlyContinue |
Select-Object @{ n = 'DC'; e = { $dc } }, TimeCreated, Id, Message | Format-List
}
The 2887 message ends with the two counts that matter: "Number of simple binds performed without SSL/TLS" and "Number of Negotiate/Kerberos/NTLM/Digest binds performed without signing". A DC that logs 2888 instead is already rejecting them, which is the "Strong Authentication Required" side.
To get names, raise the LDAP Interface Events level. Microsoft: "You can enable this additional logging by setting the 16 LDAP Interface Events diagnostic setting to 2 (Basic)." and, for the cost, "it has a negative effect on domain controller performance, and it should be disabled when it is no longer needed." Microsoft's command (a change, but a reversible logging change; do it on one DC at a time, our habit):
:: Low-risk change, on ONE DC. Raise LDAP Interface Events to 2 (Basic) to log Event 2889 per bind (Microsoft's form)
reg query HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics /v "16 LDAP Interface Events"
Reg Add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics /v "16 LDAP Interface Events" /t REG_DWORD /d 2
Leave it long enough to cover the clients' schedules (a nightly sync, a weekly report), then group what it logged:
# Read-only. On that DC: unsigned or clear-text binds in the last 24 hours, grouped by client, identity, and binding type
# (the property order IP:port, identity, binding type is our reading of the event text; check one event with Format-List first)
Get-WinEvent -FilterHashtable @{ LogName = 'Directory Service'; Id = 2889; StartTime = (Get-Date).AddDays(-1) } -ErrorAction SilentlyContinue |
ForEach-Object {
[pscustomobject]@{
Client = $_.Properties[0].Value -replace ':\d+$', ''
Identity = $_.Properties[1].Value
BindType = $_.Properties[2].Value
}
} |
Group-Object -Property Client, Identity, BindType | Sort-Object -Property Count -Descending |
Select-Object Count, Name | Format-Table -AutoSize
Microsoft's binding types in the 2889 text: "0 - SASL Bind that does not use signing" and "1 - Simple Bind that does not support signing".
| Finding | What it means (our reading unless noted) | Next |
|---|---|---|
| Type 1 from an appliance or app with a service account | A simple bind with a password on 389, in clear text | Move it to LDAPS on 636 (Steps 3-6 for its DC) or to a signed SASL bind (Step 10) |
| Type 0 from a Windows computer | A client or app that asks for SASL without signing; Microsoft says Windows clients request signing by default, so look at the app or a local policy set to None | Step 8 (client side) |
| Type 0 or 1 from an IP you can't place | Microsoft: "Identify the make, model, and type of device for each IP address cited by:" Event 2889 | Find the owner before anything else |
| No 2889 after a full cycle, and 2887 counts are zero | Nothing on this DC binds unsigned | Repeat on the next DC |
Then turn it back down. Microsoft's revert: Reg Add HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics /v "16 LDAP Interface Events" /t REG_DWORD /d 0. The diagnostic logging article: "Make sure that you reset the entries to 0 after you finish investigating the problem."
Step 8: Which signing policy is actually in effect on each DC? (read-only)
Microsoft maps the Domain controller: LDAP server signing requirements policy to one registry value, LDAPServerIntegrity under NTDS\Parameters, with None = 1 and Require Signing = 2. Channel binding is LdapEnforceChannelBinding in the same key (Never = 0, When Supported = 1, Always = 2). Read both on every DC, plus the policy result:
:: Read-only. On each DC: the signing and channel binding values it holds (an error means the value isn't set)
reg query HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters /v LDAPServerIntegrity
reg query HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters /v LdapEnforceChannelBinding
:: Which GPO set them (open the report and search Security Options for "LDAP")
gpresult /scope computer /h %TEMP%\dc-rsop.html
Windows Server 2025 adds a second policy. Microsoft: "The Domain controller: LDAP server signing requirements enforcement policy takes precedence over the Domain controller: LDAP server signing requirements policy." Its Not Configured state isn't neutral: "Default: Not Configured, which has the same effect as Enabled (default for new deployments)." And for upgrades and mixed domains: "During an upgrade, Windows Server preserves existing signing policies to prevent disruption; if no LDAP server signing policy exists, Windows Server 2025 requires signing by default."
| Finding | What it means (our reading unless noted) | Next |
|---|---|---|
| Only the new Windows Server 2025 DC rejects binds | No signing policy defined, so that DC requires signing by default; the older DCs still accept unsigned binds | Fix the clients from Step 7 first, then make every DC match on purpose |
LDAPServerIntegrity = 2 on some DCs, 1 on others |
DCs in different OUs, or a GPO that didn't apply everywhere | Group Policy Not Applying |
gpresult shows the setting, reg query doesn't match |
Policy not refreshed yet | Microsoft: "To apply it immediately, run gpupdate /force on your domain controllers." |
| A Windows client fails against a DC that requires signing | The client's Network security: LDAP client signing requirements may be None | Microsoft's client options are None, Negotiate signing, and Require signing |
On the client side, Microsoft's default is fine for Windows: "All currently supported versions of Windows client use LDAP signing by default as LDAP clients." And its warning for the strict setting: "Not setting one of the sides will prevent client computers from communicating with the server."
LDAPS doesn't care about this policy. Microsoft's policy reference: "This setting doesn't have any impact on LDAP simple bind through SSL (LDAP TCP/636)." So "Strong Authentication Required" on 389 doesn't mean LDAPS is broken, and fixing the certificate won't fix a clear-text bind on 389 (our reading).
Step 9: Is channel binding rejecting a TLS bind? (read-only)
Channel binding is narrower than people expect. Microsoft: it doesn't apply to "Simple bind over TLS", to "Certificate bind over TLS", or to "Non-TLS SASL sessions". It only covers SASL (usually NTLM or Kerberos through Negotiate) inside LDAPS or STARTTLS. Microsoft's settings:
| Value | Name | Behavior (Microsoft) |
|---|---|---|
| 0 | Never | "The server doesn't perform channel binding validation." |
| 1 | When supported | "Clients that support CBT must provide it. Clients that don't support CBT are still allowed. The server logs auditing events." |
| 2 | Always | "All applicable TLS and SASL clients must provide CBT. The server rejects authentication from clients that don't provide a valid token." |
Defaults, per Microsoft: on Windows Server 2025 new deployments the policy "Defaults to When supported." On Windows Server 2022 or earlier it's "Set to Never" and "The 2023-03 security updates enable CBT auditing by default on domain controllers."
# Read-only. On each DC: channel binding events from the last 7 days (3039 fail, 3040/3041 summary or reminder, 3074/3075 audit)
Get-WinEvent -FilterHashtable @{ LogName = 'Directory Service'; Id = 3039, 3040, 3041, 3074, 3075; StartTime = (Get-Date).AddDays(-7) } -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, Message | Format-List
Microsoft: "Events 3039, 3074, and 3075 can only be generated when Channel Binding is set to When Supported or Always." Per-client events also need the same "16 LDAP Interface Events" level of 2 from Step 7.
| Finding | What it means (Microsoft unless noted) | Next |
|---|---|---|
| 3041 and 3040 only | Policy is Never; 3040 counts "unprotected LDAPs binds" | Plan When supported (Step 10) |
| 3075 from a client | "The following client performed an LDAP bind over SSL/TLS and did not provide Channel Binding Information." It would be rejected under Always | Update or reconfigure that client before Always |
| 3074 from a client | It "would have failed the channel binding token validation if the directory server was configured to enforce validation of Channel Binding Tokens." | Same |
| 3039 | A bind already failed CBT under When supported or Always | That client is broken now; Step 10 |
| None of these, but TLS binds fail | Not channel binding; go back to Steps 3-6 (our reading) | Steps 3-6 |
Common false starts
| What people try | Why it misleads (our reading unless noted) |
|---|---|
| Turning LDAP signing off in the Default Domain Controllers Policy | It hides Step 7's evidence and reopens the attack Microsoft describes: "an attacker can cause a server to make decisions that are based on forged requests from the LDAP client." Fix the client, or time-box an exception on one DC |
| Setting channel binding to Never | 3039, 3074, and 3075 stop appearing because Microsoft only logs them under When supported or Always, so you lose the list of clients to fix |
| Deleting every old certificate on the DC | The certificate the DC serves may be in the NTDS store, or may be the one you need. Read Step 4 first and export what you remove |
| Restarting the DC after every certificate change | Newer DCs pick up a new certificate without a restart, and renewServerCertificate forces it. A restart also hides whether the old one was ever served |
| "It works in ldp on the DC, so LDAPS is fine" | The DC trusts its own CA. Microsoft's article checks the chain "on the client computer" (Step 5) |
Testing only Test-NetConnection
|
A TCP socket opens even with no certificate (Step 2) |
| Turning off certificate validation in the app | Gets a connection, removes the server-identity check TLS gives you |
| Pointing the app at an IP address | Avoids a name mismatch by failing every name check instead (Step 6) |
| Leaving "16 LDAP Interface Events" at 2 | Microsoft: "it has a negative effect on domain controller performance" |
Step 10: Change one link, then prove it
Only after Steps 1-9 agree on which link failed. Write down the current state first: the Step 3 certificate list with thumbprints, the Step 4 served thumbprint, the NTDS store contents, and the Step 8 reg query output from every DC (our habit). Export any certificate before you remove it.
No usable certificate, an expired one, or a missing key (Step 3). With a Microsoft Enterprise CA, Microsoft's route is certlm.msc → Personal → Certificates → All Tasks → Request New Certificate, then the Domain Controller template. Microsoft: "The Domain Controller template comes preconfigured with the correct properties for LDAPS, including:" Server Authentication, the FQDN in the SAN, and "Automatic renewal before expiration". If that enrollment fails, Certificate Autoenrollment Not Working is the next read. For a missing private key, the AskDS fix runs on the computer that generated the request, not the DC that received the certificate:
:: Change (low risk). On the computer where the request was generated: re-link the certificate to its private key (Microsoft's AskDS form; 0 is the store index)
certutil -repairstore MY 0
AskDS: "If we can't locate the private key container then we will need to request a new certificate."
A non-Microsoft CA, or a name the template doesn't cover (Steps 3 and 6). Microsoft's certreq request file, with a SAN section added from the certreq reference (DC FQDN first, our habit; names are examples):
;----------------- request.inf (Microsoft's LDAPS template, plus a SAN section) -----------------
[Version]
Signature="$Windows NT$"
[NewRequest]
Subject = "CN=DC2.contoso.com"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = TRUE
SMIME = False
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
KeyUsage = 0xa0
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.1 ; this is for Server Authentication
[Extensions]
2.5.29.17 = "{text}"
_continue_ = "DNS=DC2.contoso.com&"
_continue_ = "DNS=ldap.contoso.com"
:: Change. On the DC: create the request, submit it to the CA, then accept the issued certificate (Microsoft's commands)
certreq -new request.inf request.req
certreq -accept certnew.cer
The DC serves the wrong certificate (Step 4). Put the certificate you want into the AD DS service's store, which wins over the computer store. Microsoft's Event 1220 steps: Certificates snap-in → Service account → Local computer → Active Directory Domain Services → right-click NTDS\Personal → All Tasks → Import. Then make the DC reload without a restart. Microsoft: "A new rootDse operation that's named renewServerCertificate can be used to manually trigger AD DS to update its SSL certificates without having to restart AD DS or restart the domain controller." The LDIF from Microsoft's protocol spec, saved as renew.ldf:
dn:
changetype: modify
add: renewServerCertificate
renewServerCertificate: 1
-
:: Change (low risk). Import the rootDSE modify against the DC that should reload (-s is ours; the LDIF is Microsoft's)
ldifde -i -f renew.ldf -s DC2.contoso.com
Per the protocol spec, the account running it needs the Reload-SSL-Certificate control access right on that DC's nTDSDSA object. Microsoft also notes AD DS "detects when a new certificate is dropped into its certificate store and then triggers an SSL certificate update" by itself; the LDIF just forces it now.
The client doesn't trust the chain (Step 5). Add your root to the client's Trusted Root store and the issuing CA to Intermediate (Group Policy for Windows clients; the vendor's certificate import for an appliance). For one Windows test box, certutil can do it directly:
:: Change. On ONE Windows test client: add the root and the issuing CA (file names are examples)
certutil -addstore Root ContosoRootCA.cer
certutil -addstore CA ContosoIssuingCA.cer
If the chain is fine and only revocation fails, fix the CDP instead (Revocation Server Was Offline).
Unsigned or clear-text binds (Steps 7 and 8). Fix the client from Step 7's list, not the DC. Microsoft: "It's also quite possible that a solution for both topics consists in a single change. For example, by moving from simple bind to SASL using Kerberos or TLS with simple bind." For the badge server, that's its LDAP setting moved to port 636 with your CA imported (Steps 3-6 for the DC it uses). Then require signing on purpose, on every DC: Domain controller: LDAP server signing requirements = Require signing in the Default Domain Controllers Policy. On Windows Server 2025, leave Domain controller: LDAP server signing requirements enforcement at its default. If one application can't be fixed this week, a time-boxed exception is the enforcement policy set to Disabled with the older policy at None. Microsoft: "Disabled: The Domain controller: LDAP server signing requirements policy determines the LDAP signing requirement." Put an end date on the ticket (our habit).
Channel binding (Step 9). Start at When supported. Microsoft: "To maximize compatibility with older operating system versions (Windows Server 2008 and earlier versions), we recommend that you enable this setting with a value of 1." Move to Always only after 3039, 3074, and 3075 stay quiet on every DC. Use the Domain controller: LDAP server channel binding token requirements policy. If you test with the registry value on one DC first, Microsoft says the change is live without a restart: "LDAP server responds dynamically to changes to this registry entry."
Then prove it. For LDAPS, from the client side: re-run Step 4's served-certificate read (the new thumbprint), Step 5's certutil -verify, then Microsoft's ldp test. Microsoft: "Ensure that Port is set to 636, the Connectionless check box is cleared, and the SSL check box is selected, and then click OK." Then "RootDSE information should print in the right pane, indicating a successful connection." For signing, Microsoft's ldp simple-bind test on 389 carries its own warning: "Run it only in an isolated lab, use a nonprivileged disposable test account, and never enter production credentials." In production, Microsoft's check: "For production validation, monitor Event Viewer for Event ID 2888." The pass is the application working against every DC it can reach, no new Event 2889 from its IP, and Event 1220 gone from the DC (our reading). Then set "16 LDAP Interface Events" back to 0.
When a change is justified
| Finding | Prefer | Avoid |
|---|---|---|
| No usable certificate on the DC | Domain Controller template enrollment, or a certreq request with Server Authentication |
A self-signed certificate on a DC |
| Wrong certificate served | Intended certificate in NTDS\Personal, then renewServerCertificate
|
Deleting every certificate in the computer store |
| Client doesn't trust the chain | Root and intermediate on the client, by GPO or vendor import | Disabling certificate validation in the app |
| Name not in the certificate | The app pointed at a DC FQDN, or a reissue with the extra SAN | Connecting by IP address |
| Appliance sends simple binds on 389 | The appliance moved to LDAPS, then Require signing | Signing off in the Default Domain Controllers Policy |
| Only the Windows Server 2025 DC rejects binds | Fix the clients, then make every DC require signing | Disabling the 2025 enforcement policy with no end date |
| Clients logged in 3074 or 3075 | When supported until they're fixed, then Always | Channel binding set to Never |
FAQ
Why is LDAPS not working on my domain controller?
Most often the DC has no certificate it can use (Event 1220), serves a different certificate than the one you renewed, or serves one the client doesn't trust or can't match to the name it used. Microsoft: "There's no user interface for configuring LDAPS." A valid certificate is what turns it on.
What is Event ID 2889?
A per-bind record of an unsigned SASL bind or a clear-text simple bind on a DC, with the client IP, the identity, and the binding type (0 for SASL without signing, 1 for a simple bind). It only appears after "16 LDAP Interface Events" is set to 2; Event 2887 is the daily count that's logged without it.
What's the difference between LDAP signing and LDAPS?
Microsoft: "LDAP signing provides integrity and authenticity but not confidentiality." LDAPS (TLS on 636) encrypts the whole session, and Microsoft says signing "applies only to non-TLS SASL sessions." A simple bind needs TLS to protect the password.
Do I need to restart the domain controller after replacing the LDAPS certificate?
Usually not on current versions. Microsoft: AD DS detects a new certificate in its store, and renewServerCertificate triggers the update "without having to restart AD DS or restart the domain controller." Microsoft's enrollment steps still say to restart after the first certificate, so a restart in a maintenance window is the fallback.
What does "Strong Authentication Required" mean?
The DC requires signing and the client sent a simple bind in clear text or an unsigned SASL bind. Microsoft's ldp test shows it as "Ldap_simple_bind_s() failed: Strong Authentication Required". Find the client in Event 2889 (Step 7) and move it to LDAPS or a signed bind.
Related posts
- Certificate Autoenrollment Not Working (when the DC never gets its Domain Controller certificate)
- Revocation Server Was Offline 0x80092013 (when the client can't check the DC certificate's CRL)
- NPS Event 6273 Reason Code 16 or 22 (the same server-certificate checks for PEAP on NPS)
- Group Policy Not Applying (when the signing policy reaches some DCs and not others)
- Windows Time Not Syncing With Domain Controller (a wrong clock makes a valid certificate look expired)
Free checklist
Requiring LDAP signing before anyone read Event 2889 is enforcement before audit, and so is turning it back off domain-wide when one badge server breaks. A Conditional Access policy enforced before anyone read the report-only results is the same mistake. The free Conditional Access pre-enforcement checklist keeps break-glass accounts, pilot groups, and report-only review on one page:
If you want the rest of the Intune runway written down for the team (enrollment hygiene, compliance phasing, break/fix cards and read-only PowerShell snapshots), the Intune & M365 Admin Starter Pack pairs with this triage: https://cashflow4375.gumroad.com/l/joonf?utm_source=devto&utm_medium=article&utm_campaign=aps_first_sale&utm_content=ldaps-not-working-domain-controller
Admin Pack Studio; not affiliated with Microsoft. Steps 1-9 favor read-only checks: Test-NetConnection, Get-NetTCPConnection, Get-WinEvent, Get-ChildItem Cert:\LocalMachine\My, certutil -verifystore, -store, and -verify -urlfetch, the .NET SslStream read of the served certificate, Test-Certificate, Resolve-DnsName, Get-ADDomainController, reg query, gpresult, and ldp.exe connects. Raising and lowering "16 LDAP Interface Events", requesting, accepting, importing, or repairing certificates, renewServerCertificate, adding CA certificates to client stores, and changing LDAP signing, signing enforcement, or channel binding policy are deliberate changes. Change one link at a time, test from the failing client against every DC it can reach, and check current Microsoft Learn for version-specific behavior.
Top comments (0)