Fixing common SSL errors
The error codes browsers and command-line tools print, translated into the cause and the one change that usually fixes it.
Browsers and command-line tools report certificate problems as short codes that say almost nothing about the cause. Below, each code is paired with what it actually means and the one thing that usually fixes it. If you only have the domain name, start with the Domain SSL Checker — it names the failure before you go changing config.
The chain is broken
NET::ERR_CERT_AUTHORITY_INVALID · SEC_ERROR_UNKNOWN_ISSUER · curl (60) unable to get local issuer certificate · PKIX path building failed
The client cannot connect your certificate to a root it trusts. In practice this is almost always a missing intermediate: you installed the leaf certificate alone, and your own browser hides the mistake because it cached the intermediate from another site. Other people's browsers, curl, Java and mobile apps do not.
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null | grep -c "BEGIN CERTIFICATE"A result of 1 is the bug. You should see the leaf plus at least one intermediate.
- Serve the fullchain, not the leaf. nginx
ssl_certificate, ApacheSSLCertificateFileand Node'scertall want leaf + intermediates in one file. The Chain Builder assembles it if the CA sent you loose files. - Windows and IIS are different. IIS sends whatever is in the machine's intermediate store, so it can look fine locally and fail everywhere else — import the intermediate on the server itself.
- Java has its own trust store.
PKIX path building failedfrom an old JRE can also mean the root is genuinely absent fromcacerts, not that your chain is wrong. - A self-signed certificate produces the same error and no chain fix will help — it is untrusted by design. Use it for local development only.
The name does not match
NET::ERR_CERT_COMMON_NAME_INVALID · SSL_ERROR_BAD_CERT_DOMAIN · certificate is not valid for …
The hostname in the address bar is not in the certificate's SAN list. The Common Name field is ignored entirely by modern browsers, so a certificate that "has the right CN" still fails if the SAN list is missing that name.
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -ext subjectAltName- The apex and
wwware two different names. Both must be listed, or the one you missed will break. - A wildcard covers one level only.
*.example.commatchesapi.example.combut nota.b.example.com, and not the bareexample.com. - Wrong virtual host? If the SAN list belongs to a completely different site, the server picked the default vhost — usually a missing or misspelled
server_name, or a certificate bound to an IP rather than a name. - Reissue rather than patch. Adding a name means a new CSR and a new certificate; the CSR Generator and CSR Decoder are worth one pass each before you submit.
The dates are wrong
NET::ERR_CERT_DATE_INVALID · SEC_ERROR_EXPIRED_CERTIFICATE · certificate has expired
Either the certificate really has expired, or the client's clock is off. Check which before touching the server — a device with a wrong date reports this on every HTTPS site, not just yours.
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates- Renewed but still expired? The new file is on disk and the old one is in memory. Reload the server — and check you renewed the path the config actually points at.
- An intermediate can expire on its own, independently of your leaf, and takes the site down the same way.
- Fix the cause, not the instance. The maximum lifetime has been 200 days since March 2026 and drops to 47 by 2029 — see verifying and renewing.
The handshake fails outright
ERR_SSL_PROTOCOL_ERROR · ERR_SSL_VERSION_OR_CIPHER_MISMATCH · SSL_ERROR_NO_CYPHER_OVERLAP
No certificate was ever examined — client and server could not agree on how to talk. The TLS Version Check shows which protocol versions the server actually accepts.
- Nothing is listening for TLS on that port. A plain HTTP server on 443 produces exactly this. So does a firewall closing the port mid-handshake.
- The client is too old, or the server is. After disabling TLS 1.0/1.1, anything ancient stops connecting; a server offering only TLS 1.3 loses old clients too.
- Key type versus cipher list. An ECDSA certificate with an RSA-only cipher suite list is a mismatch that looks like a protocol failure.
- SNI. Without
-servernameinopenssl, or from a client that omits SNI, you reach the default site rather than yours.
The server will not start
key values mismatch · SSL_CTX_use_PrivateKey_file failed · PEM routines: no start line
Config-time failures, before any client is involved. The first is the common one: the certificate and the private key are not a pair, usually because a second CSR was generated during a re-issue and the matching key was overwritten.
openssl x509 -in cert.pem -noout -pubkey | openssl sha256; openssl pkey -in example.com.key -pubout | openssl sha256Two identical digests means they match. The Key Matcher does the same check in your browser.
- No start line means the file is not PEM — it is DER, PKCS#7 or PKCS#12. Unpack it with the Format Converter.
- An encrypted key stops an unattended start: the server is waiting on a passphrase nobody will type.
- Permissions. The key should be
0600and owned by the user the process starts as — not the one it drops to. - If the key is truly gone, the certificate is unusable. Generate a new key and re-issue; there is no recovery path.
The certificate is fine and it still looks wrong
- No padlock, no error. Mixed content — the page is HTTPS but pulls a script or image over
http://. The browser console names the offending URL. - NET::ERR_CERT_REVOKED. The CA withdrew the certificate, usually after a key compromise or a validation problem. Re-issue with a new key; do not attempt to bypass it.
- No "proceed anyway" link. HSTS is in force, which is the point of it. Fix the certificate, or clear the entry at
chrome://net-internals/#hstswhile developing. - Fixed, but the browser disagrees. TLS sessions are cached and so is HSTS. Retry in a private window, or with
curl -sv, before concluding the fix failed. - A certificate you did not order. The CT Log Search lists everything any CA has issued for your domain; a CAA record stops it happening again.