Skip to content

SSL Certificate Checker

An SSL certificate checker opens a real TLS connection to a host and reports what the server presented: the leaf certificate, its validity window, the chain sent alongside it, and whether that chain verifies against a browser trust store. This tool checks all four conditions a browser applies before it shows the padlock.

The four conditions every browser checks

A certificate is not simply "valid" or "invalid". A browser runs four independent tests, and a failure in any one of them produces a full-page interstitial. Reading them separately is the difference between a five-minute fix and an afternoon of guessing.

  1. Validity window. The current time must fall between notBefore and notAfter. Failing this gives Chrome ERR_CERT_DATE_INVALID — which also fires when the *client* clock is wrong, so check the visitor's date before you blame the server.
  2. Hostname match. The name in the address bar must match an entry in the Subject Alternative Name extension. Common Name has been ignored by Chrome since version 58 and by Firefox since 48; a certificate with only a CN and no SAN fails everywhere. Wildcards match exactly one label: *.example.com covers www.example.com but not example.com itself and not a.b.example.com.
  3. Chain to a trusted root. The server must send the leaf plus every intermediate needed to reach a root the client already trusts. The root itself is deliberately not sent — it is already in the trust store.
  4. Signature and revocation. Every signature in the path must verify, the algorithms must still be acceptable (SHA-1 signatures are rejected outright), and the certificate must not be revoked via OCSP stapling or CRLSets.
This tool performs two handshakes: one with verification disabled, so the certificate can be displayed even when it is broken, and one with full verification, so the "trusted" verdict is OpenSSL's real answer rather than an opinion.

How to read the result

Days remaining

The headline number counts down to notAfter in UTC. Automated issuance (ACME, Let's Encrypt, ZeroSSL, most managed hosts) renews at roughly one third of the lifetime remaining — 30 days for a 90-day certificate. If a certificate that should auto-renew is inside 20 days, renewal is failing silently; check the ACME client's logs and its ability to answer the HTTP-01 or DNS-01 challenge. Certificate lifetimes are shrinking industry-wide, so any process that depends on a human remembering a date will eventually fail.

Read the full explanation of ssl certificate checker results ↓

Chain complete / incomplete

This is the single most common production TLS bug, and the most confusing, because it is *invisible from a laptop that has already cached the intermediate*. If the server sends only the leaf, Chrome on your desktop may still succeed — it fetches the missing issuer via the Authority Information Access extension or has it cached from another site. Safari, most Android versions, curl on a minimal container, Java clients, and payment gateways do not. The symptom is "it works for me, but the API integration says unable to get local issuer certificate".

The fix is always the same: concatenate the leaf and the CA-supplied intermediate bundle into the file your server points ssl_certificate (nginx) or SSLCertificateFile (Apache 2.4.8+) at, leaf first. In nginx that single file must contain the full chain — this is exactly what Certbot's fullchain.pem is, and using cert.pem instead is the classic mistake.

Hostname mismatch

The SAN list shown below the verdict is the complete set of names this certificate covers. A mismatch almost always means one of three things: the request hit a default virtual host because SNI was not sent or not configured, the certificate covers the apex but you are testing www (or the reverse), or a CDN is terminating TLS with its own certificate for a hostname you have not added to the CDN configuration.

Self-signed and untrusted

A self-signed certificate has an identical subject and issuer — it vouches for itself. That is fine for an internal service where you distribute the certificate to clients, and fatal for anything a browser visits. "Not trusted" without "self-signed" usually means a private CA (common behind corporate proxies) or an intermediate that expired independently of the leaf.

Common failures and their fixes

SymptomCauseFix
ERR_CERT_DATE_INVALID on one machine onlyClient clock is wrongFix NTP on the client; the certificate is fine
ERR_CERT_AUTHORITY_INVALIDSelf-signed, private CA, or missing intermediateInstall the CA bundle; check "chain complete" above
unable to get local issuer certificate from curl onlyIncomplete chain masked by browser AIA fetchingServe fullchain.pem, not cert.pem
ERR_CERT_COMMON_NAME_INVALIDHostname not in the SAN listReissue with every hostname you serve, or fix SNI/vhost routing
Certificate is correct on disk but stale over the wireServer never reloaded after renewalnginx -s reload / systemctl reload apache2; add a deploy hook to the ACME client
Renewal succeeds but the old certificate is servedA CDN or load balancer terminates TLS ahead of the originRenew at the edge — check the certificate hostname and issuer reported above
Renewing a certificate does nothing until the process holding port 443 re-reads it. Every ACME client supports a deploy or renew hook — wire the reload in there, not into a cron job you will forget.

The same checks with openssl

Everything on this page comes from an ordinary TLS handshake, and openssl s_client gives you the same data from any shell. The -servername flag is not optional: without it no SNI is sent and a shared host will hand you the wrong certificate entirely.

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

subject=CN=example.com
issuer=C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
notBefore=Jul 29 22:10:08 2026 GMT
notAfter=Oct 27 22:17:21 2026 GMT
Subject, issuer, and validity dates
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -ext subjectAltName

X509v3 Subject Alternative Name:
    DNS:example.com, DNS:*.example.com
Every hostname the certificate covers
echo | openssl s_client -connect incomplete-chain.badssl.com:443 \
  -servername incomplete-chain.badssl.com -showcerts 2>/dev/null \
  | grep -E "Verify return code|^ *[0-9]+ s:|^ *[0-9]+ i:"

 0 s:CN=*.badssl.com
    Verify return code: 21 (unable to verify the first certificate)
Chain and verification verdict — "Verify return code: 21" means a missing intermediate
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -checkend 2592000
# "Certificate will not expire" -> exit 0
# "Certificate will expire"     -> exit 1  (alert on this)
Exit-code check for monitoring: non-zero when the certificate expires within 30 days

For a non-443 service — SMTP on 587, IMAP on 993, a database with TLS — add -starttls smtp (or imap, pop3, postgres) so OpenSSL negotiates the protocol upgrade before the handshake. This tool accepts any port in the field above and speaks TLS directly, which is what implicit-TLS ports such as 465 and 993 expect.

Certificate hygiene worth automating

  • Publish a CAA record so only your chosen CA can issue for the domain. It costs one DNS record and blocks an entire class of mis-issuance.
  • Alert at 21 days remaining, not 7. A failed ACME renewal usually needs a DNS or firewall change, and that takes longer than a week to get approved in most organisations.
  • Monitor the certificate the *edge* serves, not the one on the origin disk. If Cloudflare, Fastly, or a load balancer terminates TLS, that is the certificate visitors actually see.
  • Check every hostname separately. Apex and www frequently diverge after a migration, and only one of them is usually monitored.
  • After any change, confirm the response really is coming from the new certificate by comparing the SHA-256 fingerprint shown above with the one on the server.

Once TLS is healthy, the next things worth checking are the HTTP response headers your server sends and their security header grade — HSTS in particular only makes sense once the certificate chain is reliably correct.

Frequently asked questions

Why does my site work in Chrome but fail in Safari or on Android?
Almost always an incomplete chain. Chrome can fetch a missing intermediate over AIA or reuse one it cached from another site; Safari and older Android cannot. The "chain complete" verdict above tells you definitively — if it says incomplete, serve the full chain file (fullchain.pem rather than cert.pem) and reload the web server.
What does "Verify return code: 21" from openssl mean?
Code 21 is "unable to verify the first certificate": the server sent a leaf whose issuer OpenSSL cannot find, because the intermediate was not included in the handshake. It is the command-line equivalent of the incomplete-chain result on this page. Codes 10 (certificate has expired) and 18 (self-signed certificate) are the other two you will see regularly.
Does a wildcard certificate cover the apex domain?
No. *.example.com matches exactly one label in that position, so it covers www.example.com and api.example.com but not example.com itself, and not a.b.example.com. Certificate authorities normally add the apex as a second SAN entry when you request a wildcard — check the SAN list above to confirm yours did.
I renewed the certificate but this tool still shows the old expiry date.
The new file is on disk but the running process is still holding the old one in memory. Reload nginx (nginx -s reload) or Apache (systemctl reload apache2) and re-run the check. If it still shows the old certificate, TLS is being terminated somewhere ahead of your origin — a CDN, load balancer, or reverse proxy — and that is where the renewal has to happen.
How many days before expiry should I renew?
Renew at one third of the remaining lifetime and alert at 21 days. ACME clients do this automatically for 90-day certificates, renewing at day 60. The reason to alert early rather than at 7 days is that most renewal failures require a change to DNS, a firewall, or a challenge path, and those changes are rarely same-day in a real organisation.
Is a self-signed certificate ever acceptable?
For internal services where you control every client and can distribute the certificate or its CA into their trust stores, yes — the encryption is identical. For anything a browser reaches over the public internet, no: users will be trained to click through a warning, which destroys the value of the warning. Free automated CAs have made the trade-off unnecessary.
What key size and signature algorithm should I be using?
RSA 2048-bit or ECDSA P-256 are both fine; ECDSA P-256 is faster and produces smaller handshakes. The signature algorithm must be SHA-256 or stronger — every browser rejects SHA-1 signatures on publicly trusted certificates. This tool reads the algorithm out of the certificate DER rather than assuming it, so the value shown is the real one.
Can I check a certificate on a port other than 443?
Yes — put the port in the field next to the hostname. This works for any service speaking TLS immediately on connect: 465 (SMTPS), 993 (IMAPS), 995 (POP3S), 8443, and so on. Ports that use STARTTLS to upgrade a plaintext session (587 SMTP submission, 143 IMAP) negotiate differently; use openssl s_client -starttls smtp -connect host:587 for those, or check reachability with the port checker.