When a browser throws an SSL warning, it's reporting one of a small set of concrete failures: the certificate expired, the name doesn't match, the chain doesn't reach a trusted root, or the server is offering protocols nobody should accept anymore. Each has a distinct cause and a distinct fix. "The SSL is broken" is never the diagnosis; the job is to find out which check failed.
This guide walks the checks in the order a TLS client effectively performs them, then closes with the part most teams skip: making sure you hear about the next expiry before your customers do.
Step 1. Pull the certificate details
Open the SSL Certificate Checker and enter your hostname. The tool connects to port 443, performs a TLS handshake, and reports what the server actually presented: issuer, validity window, subject alternative names, the full chain, and protocol support.
That last clause matters: you're testing what the server sends, not what's sitting in a file somewhere. A renewed certificate that was never deployed, or deployed to one node behind a load balancer but not the others, only shows up when you check the live endpoint. (For the multi-node case: check repeatedly, or check each node's IP directly if you can.)
For a local cross-check, OpenSSL shows the same data:
openssl s_client -connect example.com:443 -servername example.com </dev/null \ | openssl x509 -noout -dates -subject -issuer
The -servername flag matters: it sets SNI, and without it a server hosting multiple certificates may hand you the wrong one, sending you down a false trail.
Step 2. Check the expiry window
The single most common SSL failure is also the most preventable: the certificate expired because renewal was manual, or automated renewal broke silently months ago.
Look at the Not After date. Then apply the real rule: a certificate expiring in 20 days isn't "fine," it's a deadline. Publicly trusted certificates are capped at 398 days, Let's Encrypt issues for 90, and the industry is moving shorter, which means renewal frequency only increases, and with it the number of chances for automation to fail.
While you're here, check Not Before too. A certificate that isn't valid yet (clock skew during issuance, or a misdeployed future cert) produces the same browser error as an expired one, and it's the variant people don't think to look for.
Step 3. Verify the name matches (SAN coverage)
The hostname the client requested must appear in the certificate's Subject Alternative Names. The Common Name field is ignored by modern browsers; SAN is the only list that counts.
Frequent mismatch patterns:
- Apex vs
www. The certificate coverswww.example.combut notexample.com, or vice versa. Both need to be in the SAN list (or covered by redirect-before-TLS, which doesn't exist; the TLS handshake happens first, so both names need valid certs). - Wildcard depth.
*.example.commatchesapi.example.combut nota.b.example.comand not the apexexample.com. One level only. - Forgotten subdomains. A service moved to a new subdomain that nobody added to the cert at reissue time.
The certificate checker lists every SAN entry; verify each hostname users actually hit appears there.
Step 4. Validate the chain
A leaf certificate alone proves nothing: the client must build a path from it through intermediate certificates to a root it already trusts. The server is responsible for sending the leaf plus all intermediates.
The classic failure is the incomplete chain: the server sends only the leaf. Browsers often paper over this (caching intermediates, or fetching them via the AIA extension), so the site "works in Chrome" while curl, Java clients, older Android, and monitoring agents all fail with "unable to get local issuer certificate." If your API works in a browser but mobile apps or scripts choke on TLS, suspect a missing intermediate before anything else.
The checker reports the chain as presented. Confirm:
- Every intermediate between the leaf and the root is present, in order.
- Each certificate in the chain is itself unexpired; an expired intermediate takes down every leaf under it, and it's a failure mode people forget exists (the AddTrust root expiry in 2020 was exactly this, breaking swaths of the internet at once).
- The chain terminates at a CA that's actually in current trust stores.
The fix for an incomplete chain is server config: deploy the "fullchain" bundle your CA provided, not just the certificate file.
Step 5. Check protocols and cipher strength
A valid certificate served over a broken protocol is still a security problem. Current state of play:
- TLS 1.2 and TLS 1.3: the only versions that should be enabled. TLS 1.3 preferred.
- TLS 1.0 and 1.1: formally deprecated by RFC 8996 (2021). Browsers dropped them in 2020. If your server still offers them, compliance scans (PCI DSS among others) will flag it.
- SSLv3 and SSLv2: actively exploitable (POODLE and friends). These should not respond at all.
Also check the signature and key parameters on the certificate itself: RSA keys should be 2048-bit minimum, and the signature algorithm should be SHA-256 or better; SHA-1 signatures have been rejected by browsers since 2017, so finding one usually means an internal CA that needs updating.
If you run an internal CA for private services, all the same checks apply; the only difference is that you maintain the trust store, which means chain problems are even easier to create and harder to notice.
Step 6. Fix what you found
Mapping findings to fixes:
| Finding | Fix |
|---|---|
| Expired / expiring leaf | Renew and deploy; then fix the automation that let it get close |
| Not-yet-valid cert | Check server clocks and which cert got deployed |
| SAN mismatch | Reissue with the full hostname list; mind wildcard depth |
| Incomplete chain | Serve the fullchain bundle, restart, re-test |
| Expired intermediate | Get the current intermediate from your CA, update the bundle |
| TLS 1.0/1.1/SSLv3 enabled | Disable in server config; allow only TLS 1.2+ |
After any change, re-run the certificate checker against the live endpoint. Config edits that never got reloaded are their own classic failure.
Step 7. Stop doing this manually
Everything above is a point-in-time check, and certificates fail on a schedule. The renewal cron dies, a DNS change breaks the ACME challenge, a vendor cert nobody owns expires on a Saturday. The fix is a monitor that checks the live endpoint daily and alerts at sensible thresholds.
Set one up at SSL certificate expiry monitoring; it watches the certificate your server actually serves and alerts ahead of expiry, which also catches the "renewed but never deployed" case that file-based checks miss. The full walkthrough is in how to set up SSL monitoring.
Alert thresholds that work in practice: first warning at 30 days (time to fix automation calmly), escalation at 14 and 7. An alert that fires the day before expiry is a pager, not a monitor.
TL;DR
- Run the SSL Certificate Checker against the live hostname; it tests what's actually served.
- Expiry: check Not After and Not Before; treat <30 days as actionable.
- Names: every public hostname must be in the SAN list; wildcards cover one level only.
- Chain: leaf plus all intermediates, each one unexpired; "works in Chrome, fails in curl" means missing intermediate.
- Protocols: TLS 1.2/1.3 only; anything older is a finding.
- Re-test after every fix.
- Put a certificate expiry monitor on it so the next problem finds you first.
Related
- SSL Certificate Checker: the on-demand check this guide is built around
- How to set up SSL certificate monitoring: the continuous version
- DNS Lookup tool: when the cert is fine but the hostname resolves somewhere unexpected
