Guide · SSL & Security

SSL/TLS Certificate Errors Explained: Causes, Diagnosis and Fixes

Decode browser errors like ERR_CERT_COMMON_NAME_INVALID and ERR_CERT_AUTHORITY_INVALID, diagnose them with openssl and curl, and fix each root cause.

By SiteDownCheck Editorial · Updated October 4, 2026 · 10 min read

A certificate warning is the browser telling you that it could not prove the server is who it claims to be, or that the encrypted channel could not be set up at all. After reading this guide you will be able to match the exact error string to its underlying cause, confirm that cause from the command line, and apply the right fix instead of guessing.

How a browser decides to trust a certificate

Every HTTPS connection begins with a TLS handshake. The server presents a certificate chain: a leaf certificate for your hostname, usually one or more intermediate certificates, and (implicitly) a root that is already stored in the visitor's operating system or browser trust store. The client then checks several things:

  1. The current time falls between the certificate's Not Before and Not After dates.
  2. The hostname the user typed appears in the certificate's Subject Alternative Name (SAN) list. The old Common Name field is ignored by modern browsers.
  3. The chain links up: each certificate is signed by the next one, ending at a root the client trusts.
  4. The certificate has not been revoked, as far as the client can tell.
  5. The client and server agree on a TLS version and cipher suite that both support.

Each failure mode produces a different message, and the message is the fastest clue you have. Chrome and Edge show NET::ERR_... codes, Firefox shows SEC_ERROR_... or SSL_ERROR_... codes, and Safari uses plainer wording.

Quick reference: symptom, cause, fix

Browser messageMost likely causeFix
NET::ERR_CERT_DATE_INVALID / SEC_ERROR_EXPIRED_CERTIFICATECertificate expired, or visitor's clock is wrongRenew and reload the web server; if only one user is affected, check their clock
NET::ERR_CERT_COMMON_NAME_INVALID / SSL_ERROR_BAD_CERT_DOMAINHostname not listed in the certificate's SAN, or wrong vhost answeringReissue with all hostnames, or fix the virtual host / SNI configuration
NET::ERR_CERT_AUTHORITY_INVALID / SEC_ERROR_UNKNOWN_ISSUERSelf-signed certificate, private CA, or missing intermediateInstall a certificate from a public CA and serve the full chain
Works in Chrome, fails in curl, Java or AndroidIncomplete chain (intermediate not sent)Serve fullchain.pem, not cert.pem
ERR_SSL_PROTOCOL_ERROR / SSL_ERROR_RX_RECORD_TOO_LONGServer not speaking TLS on that port, TLS version mismatch, or proxy misconfigurationCheck what is listening on 443; enable TLS 1.2/1.3
NET::ERR_CERT_REVOKEDCA revoked the certificateIssue a new certificate with a new key
Error on one device onlyWrong system date, interception software, or outdated trust storeFix the device, not the server

Expired certificates

This is the most common failure and the most avoidable. The browser shows ERR_CERT_DATE_INVALID and the visitor must click through a warning that most people will not bypass.

Check the dates from any machine with OpenSSL:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates -subject -issuer

You will see notBefore and notAfter. If notAfter is in the past, the certificate expired. Renewal itself is covered in our guide to renewing and automating SSL certificates.

A frequently missed detail: renewing the file on disk does not change what the server serves. Nginx, Apache and most proxies load certificates at start-up or reload. If certbot succeeded but the site still shows the old date, reload the service (systemctl reload nginx). Also check whether something else terminates TLS in front of your server, such as a load balancer, a CDN or a control-panel proxy that holds its own copy.

Name mismatch: ERR_CERT_COMMON_NAME_INVALID

The certificate is valid and trusted, but it was issued for different names than the one the visitor typed. Typical triggers:

  • The certificate covers example.com but not www.example.com, or the reverse.
  • A wildcard *.example.com covers shop.example.com but not example.com itself, and not a.b.example.com. A wildcard matches exactly one label.
  • The server has several virtual hosts and the request landed on the default one, which has a different certificate. This happens when SNI (Server Name Indication) is not being used or the server_name / ServerName directive is missing.
  • DNS points a new hostname at a server that has never been configured for it.
  • You reached the site by IP address or by a CNAME to a provider hostname.

List the names actually present in the certificate:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -ext subjectAltName

If the output lacks the hostname in the address bar, reissue the certificate with every needed name. If the names are right but you see the wrong certificate, test without SNI to confirm you have a default-vhost problem:

echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -subject

Whichever certificate this prints is your default. Make sure the default server block either holds a sensible certificate or rejects the handshake deliberately.

Untrusted issuer: ERR_CERT_AUTHORITY_INVALID

Chrome shows this when it cannot build a path from your leaf certificate to a root it trusts. There are three distinct causes and they need different fixes.

Self-signed certificate

The leaf certificate signed itself. This is fine for a local test box and wrong for anything public. Replace it with a certificate from a public CA. Let's Encrypt is free and automatable.

Private or corporate CA

Internal certificates issued by your company CA work only on devices that have that root installed. If the site is meant to be public, use a public CA. If it is internal, deploy the root through device management.

Incomplete chain

The server sends only the leaf, not the intermediate that signed it. Many desktop browsers can fetch the missing intermediate from the URL in the certificate's Authority Information Access extension, or they have it cached from other sites, so the page loads fine for you. Other clients do not do that: curl, OpenSSL, many API clients, older Android versions and some monitoring tools will fail. This is why "it works in my browser" is not proof that the chain is correct.

Check how many certificates the server sends:

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
  | grep -E '^( [0-9]+ s:|   i:|Verify return code)'

You should see the leaf at depth 0 and at least one intermediate at depth 1. A final line of Verify return code: 21 (unable to verify the first certificate) or 20 (unable to get local issuer certificate) indicates a broken chain. The SSL Chain Debugger shows the same thing without needing a shell.

The fix is to configure the server with the full chain file:

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;  # leaf + intermediates
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

In Apache 2.4.8 and later, SSLCertificateFile accepts the full chain file too, and the separate SSLCertificateChainFile directive is deprecated. For commercial certificates, concatenate in order: your leaf first, then the intermediate(s). Do not include the root; clients already have it.

ERR_SSL_PROTOCOL_ERROR and handshake failures

This message is vaguer: the TLS conversation could not even start properly. Common causes:

  • Nothing is speaking TLS on port 443. The service may be plain HTTP, down, or a firewall or proxy is returning something else. Test with curl -vI https://example.com and look at where it stops.
  • TLS version or cipher mismatch. Servers that only allow TLS 1.0/1.1 are rejected by current browsers, and a server restricted to a narrow cipher list may share nothing with the client. Use the TLS Version Checker to see what your server offers, and enable TLS 1.2 and 1.3.
  • CDN or proxy mode mismatch. If a CDN expects HTTPS to the origin but your origin has no certificate on 443, handshakes fail. Cloudflare-specific cases are listed in Cloudflare 520-526 errors explained.
  • Unsupported client. Very old operating systems cannot negotiate modern protocols.
  • Antivirus or corporate proxy interception that breaks the handshake on the visitor's machine.

Reproduce the handshake with a forced version to see which side refuses:

openssl s_client -connect example.com:443 -servername example.com -tls1_2 </dev/null
openssl s_client -connect example.com:443 -servername example.com -tls1_3 </dev/null

Wrong system clock

If a visitor sees a date error on every HTTPS site, or on none of yours but only on their machine, the device clock is wrong. Certificates are checked against the local time, so a device set to 2019 will reject a certificate issued last month, and a device set far in the future will think everything expired. Laptops with dead clock batteries and virtual machines restored from old snapshots are the usual culprits. Ask the user to enable automatic time sync; nothing on the server will help.

The same logic applies to your own servers. If a build agent or container has no working NTP, outbound API calls will fail with certificate errors that look like server faults.

Revoked certificates

NET::ERR_CERT_REVOKED means the issuing CA declared the certificate invalid before its expiry, typically because the private key was exposed or the certificate was issued in error. Revocation checking varies a lot between clients: Chrome relies mostly on its own pushed revocation lists rather than live lookups, Firefox has its own mechanism, and curl may not check unless asked. Do not rely on revocation behaving identically everywhere.

If your certificate is revoked, generate a new private key, request a new certificate, and install it. Reusing the old key defeats the purpose. Then audit how the key leaked.

Diagnosing with curl

curl -vI is a quick way to see the handshake, the verification result and the HTTP response in one go:

curl -vI https://example.com 2>&1 | grep -E 'SSL|TLS|subject|issuer|expire|HTTP/'

Useful variations:

  • curl -k ignores verification. Use it only to prove that the certificate is the problem; if -k works and plain curl does not, the issue is trust or chain, not connectivity.
  • curl --resolve example.com:443:203.0.113.10 https://example.com/ forces a specific server IP, which is excellent for checking one node behind a load balancer or testing a new server before DNS changes.
  • curl --cacert chain.pem https://example.com/ tests against a specific trust bundle.

Prevention

Most certificate outages are process failures, not technical ones. A short checklist:

  • Automate issuance and renewal, and test the renewal path as described in how to renew an SSL certificate and automate it.
  • Monitor expiry from outside your network. An external SSL Checker run, or an uptime monitor with certificate expiry alerts, catches problems your internal tooling might miss, including the "renewed on disk but never reloaded" case. If you manage many domains, the Bulk SSL Checker gives one overview.
  • Include every hostname you serve, including www and any API subdomains, when requesting certificates.
  • Keep a record of where certificates are installed: CDN, load balancer, mail server, control panel. Forgotten copies are what expire.

Next steps

FAQ

Why does my site show a certificate error only on some devices?

Usually the cause is on the device: an incorrect clock, an outdated operating system trust store, or security software intercepting HTTPS. It can also be an incomplete chain, because some clients can fetch missing intermediates and others cannot. Test with openssl s_client and an external checker to separate server faults from client faults.

Can I just click "proceed anyway"?

You can on a site you control, to investigate. For visitors it is a poor outcome: most will leave, and browsers add friction deliberately. Fix the certificate rather than training users to bypass warnings.

Is a self-signed certificate ever acceptable?

For local development, internal test systems or devices where you install the certificate yourself, yes. For a public website it will always trigger a trust warning. Free public CAs make it unnecessary.

My certificate is valid but the browser still complains about the name. Why?

Check the SAN list, not the subject line. The hostname must appear there exactly, or match a single-label wildcard. Also verify that the request reaches the correct virtual host, since a default server block with another certificate produces the same error.

Will renewing the certificate fix a revoked-certificate error?

Renewing with the same private key might not, and it is the wrong approach anyway. Generate a fresh key pair and a new certificate, install it, then reload the server.

How can I be warned before a certificate expires?

Use an external monitor that checks the certificate your server actually serves and alerts at several thresholds, for example 30, 14 and 7 days. Internal cron jobs that only read the file on disk will miss deployment mistakes.

Get notified when this guide updates

Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.

This page is general information written by our editorial team and updated when documentation changes. Servers and providers differ, so test changes safely first. See our editorial policy and disclaimer.