Windows Server · TROUBLESHOOTING

Windows Server Certificate Troubleshooting Checklist

Troubleshoot Windows Server certificate problems by checking certificate stores, expiration, trust chains, private keys, bindings and permissions.

Practical Runbook 10 Steps Issues → Solutions → Recommendations
! Issue

Troubleshoot Windows Server certificate problems by checking certificate stores, expiration, trust chains, private keys, bindings and permissions.

✓ Solution

Identify which certificate is actually being presented, confirm expiry and trust chain, then verify the private key and binding are intact.

★ Recommendations

Renew or replace certificates before expiry rather than after — most certificate incidents are entirely preventable with an expiry alert.

01

What to check first

Certificate problems usually present as a browser/client trust error, but the underlying cause is one of five things: the wrong certificate is bound, the certificate expired, the chain doesn't validate, the private key is missing or inaccessible, or the binding itself is broken. Identify which of these it is before touching IIS or the certificate store — each has a different fix.

02

Identify the certificate actually being presented

Don't assume the certificate you think is bound is the one being served — check what the client actually receives:

$conn = New-Object System.Net.Sockets.TcpClient("hostname", 443)
$stream = New-Object System.Net.Security.SslStream($conn.GetStream())
$stream.AuthenticateAsClient("hostname")
$stream.RemoteCertificate | Select-Object Subject, Issuer, GetExpirationDateString

On the server itself, list bindings directly with netsh http show sslcert for classic IIS/HTTP.sys bindings, and cross-reference the thumbprint against the certificate store.

03

Check expiration

List certificates in the local machine store sorted by expiry, so you catch ones expiring soon as well as ones already expired:

Get-ChildItem -Path Cert:\LocalMachine\My | Sort-Object NotAfter | Select-Object Subject, NotAfter, Thumbprint

Note that a certificate can be technically "not expired" but still fail validation if the server's system clock has drifted — check w32tm /query /status if the expiry check passes but trust still fails.

04

Validate the trust chain

A certificate can be valid and unexpired but still fail if the intermediate certificate isn't installed on the server, which is common right after a CA rotates its intermediates. Check the full chain:

certutil -verify -urlfetch cert.cer

Look specifically for CERT_TRUST_IS_PARTIAL_CHAIN in the output — that error means an intermediate is missing, not that the certificate itself is invalid. Install the missing intermediate from the issuing CA rather than reissuing the leaf certificate.

05

Confirm the private key is present and accessible

A certificate imported without its private key, or one where the service account lacks read permission on the key, will show as valid in the store but fail to bind. Check for the key:

$cert = Get-ChildItem Cert:\LocalMachine\My\<thumbprint>
$cert.HasPrivateKey

If HasPrivateKey is False, the certificate was imported as a public-only .cer rather than a .pfx — reimport it with the private key. If it's True but the binding still fails, check the key's ACL: right-click the certificate in certlm.msc → All Tasks → Manage Private Keys, and confirm the service account (e.g., NETWORK SERVICE or the app pool identity) has Read access.

06

Check the binding itself

For IIS, confirm the site binding points to the correct certificate thumbprint — a common failure after renewal is that the new certificate was installed but the old thumbprint is still bound:

Get-WebBinding -Name "Default Web Site" | Select-Object protocol, bindingInformation, certificateHash

Rebind explicitly if the hash doesn't match the current certificate rather than relying on IIS Manager's UI, which can silently fail to save the change.

07

Check for SNI and hostname mismatches

If multiple sites share an IP and the wrong certificate is served depending on hostname, confirm SNI is enabled on the binding and that the certificate's Subject Alternative Names actually cover the hostname being requested — a mismatch here produces a valid-but-wrong-certificate error that looks identical to an expired one at a glance.

08

Useful commands

Get-ChildItem -Path Cert:\LocalMachine\My | Sort-Object NotAfter
netsh http show sslcert
certutil -verify -urlfetch cert.cer
Get-WebBinding -Name "Default Web Site"
w32tm /query /status
09

What should be captured for escalation?

Capture the certificate's Subject, Issuer, Thumbprint and NotAfter date, the output of netsh http show sslcert for the affected binding, and the exact client-side error (expired, untrusted, name mismatch are three different problems). This lets the next engineer confirm the fix instead of re-running the whole diagnostic chain.