0X00002155

Fix ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION (0x2155) on LDAP Bind

LDAP bind failing with 0x2155 means the domain controller won't accept your unencrypted or unsigned connection. Here's how to fix it fast.

Quick answer

Your LDAP client is trying to bind to a domain controller without signing or encryption, and the DC is refusing it. Use LDAPS (port 636), StartTLS, or enable SASL signing — or temporarily relax LDAPServerIntegrity if you're diagnosing a legacy app.

Why you're seeing 0x2155

Microsoft has been tightening LDAP security since the March 2020 ADV190023 advisory, and then again in the January 2020 default changes. Domain controllers now treat unsigned, unencrypted LDAP binds as unacceptable unless you deliberately lower the bar. If your app talks to a DC on port 389 with a plain simple bind and no TLS, you'll get ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION — decimal 8533, hex 0x2155. The DC is basically saying: I need packet privacy or better before I'll let you in.

I've seen this hit hardest with older Java apps using JNDI, PHP ldap_bind() against an unencrypted URI, and homegrown PowerShell scripts using [System.DirectoryServices.DirectoryEntry] with an LDAP:// path and no AuthenticationTypes. The minute Windows Server 2019 or 2022 domain controllers enforce LDAP signing, every one of those breaks at once. It also shows up on hybrid setups where a Linux appliance (NAS, VoIP PBX, backup appliance) tries to do simple binds over 389.

Fix it step by step

  1. Confirm the error. Grab the full error string and the LDAP result code from your app. On Windows DCs, look for Event ID 2887 (unsigned binds summary) or 2889 (unsigned simple bind attempts) in the Directory Service log. Those events name the client IP and the offending bind type.
  2. Move to LDAPS on 636. The cleanest fix. Point your app at ldaps://dc01.corp.local:636 instead of ldap://dc01:389. Confirm port 636 is listening:
    Test-NetConnection dc01.corp.local -Port 636
    
    If it fails, install the DC's root CA cert on the client and confirm the DC has a valid server-auth certificate issued to its FQDN.
  3. Or enable StartTLS on 389. Some apps can't switch to 636 but support the StartTLS extended operation. In PHP:
    ldap_start_tls($conn);
    In .NET, use AuthenticationTypes.SecureSocketsLayer. Java JNDI needs com.sun.jndi.ldap.connect.pool=true plus a proper SSL socket factory — messy, which is why 636 is usually easier.
  4. Or enable SASL signing (Negotiate or Kerberos). If you can't do TLS at all, at least sign. On Windows clients, use AuthenticationTypes.Signing (and ideally Sealing).
    $entry = New-Object System.DirectoryServices.DirectoryEntry(
      "LDAP://dc01.corp.local",
      "user@corp.local",
      "password",
      [System.DirectoryServices.AuthenticationTypes]::Secure -bor
      [System.DirectoryServices.AuthenticationTypes]::Signing
    )
    Kerberos-based binds are automatically signed, so switching from simple bind to Negotiate fixes it without touching TLS.
  5. Verify the DC policy. On the DC, check what's actually enforced:
    reg query "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v LDAPServerIntegrity
    reg query "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v LdapEnforceChannelBinding
    LDAPServerIntegrity = 2 means signing is required. 1 means none required (weak). Don't lower this without understanding the risk.

If the main fix doesn't work

Sometimes the app genuinely can't do signing or TLS — old Cisco Unified CM, some Xerox copiers, a 2011-era backup agent. In that case you have three realistic options:

  • Stand up an LDAPS proxy. Put stunnel or haproxy in front of 636 and let the legacy app connect to localhost:389, which forwards over TLS. This is the fix I reach for most often because it keeps the DC hardened.
  • Use a dedicated read-only service account on a specific DC and lower LDAPServerIntegrity to 1 on that one DC only. Ugly, but a documented stopgap. Set a calendar reminder to retire whatever needs it.
  • Switch the app to a Kerberos bind. Even without TLS, Kerberos-encrypted binds satisfy the packet privacy requirement. This usually means passing a UPN and letting Windows negotiate instead of a plain DN/password simple bind.

One trap: if you fix the client but the app still fails, check for a load balancer or firewall between client and DC that's terminating TLS. Some F5 and Palo Alto configs silently strip LDAPS. Run openssl s_client -connect dc01:636 -showcerts from the client to see what's really happening on the wire.

Prevention

Audit every LDAP integration in your environment before Microsoft's next hardening wave forces the issue. On each DC, enable diagnostic logging for LDAP interface events and watch for Event ID 2889 for a week — it will list every unsigned simple bind with the client IP. That list is your migration queue. Then work through it: TLS first, Kerberos second, stunnel only for the apps that genuinely can't be fixed. And when you're writing new LDAP code, default to ldaps:// and port 636. The 0x2155 error is a feature, not a bug — it's the DC telling you something insecure is trying to talk to it.

I know this error is infuriating when it pops up on a Friday afternoon. The good news: 95% of cases are fixed by switching a URI from ldap:// to ldaps:// and confirming the cert chain. Start there.
Related Errors in Network & Connectivity
0X40000011 STATUS_RECEIVE_PARTIAL_EXPEDITED Fix for Windows 10/11 Unstable WiFi connection WiFi keeps disconnecting on Windows 11 23H2 0X000025F4 DNS_WARNING_DOMAIN_UNDELETED (0X000025F4): The fix for "undeleted" DNS zones Fix DHCP Not Enabled for WiFi on Windows 10/11

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.