Most SSL certificate checker tools answer one question: is this cert valid right now? That's useful for about 30 seconds. The interesting failures, chains that work in Chrome but break in curl, OCSP staples that silently degrade, certs that pass every browser check but kill your B2B webhooks, never show up in the green-lock view. After enough 2am pages, I stopped trusting any tool that just gives me a thumbs up.
This post walks through what an honest cert check actually covers, the CLI commands to run them yourself, and where one-off checking stops scaling. It's written for the engineer who has 50+ certs to babysit and has been burned at least once by a "works fine in the browser" report.
What an SSL Certificate Checker Actually Validates
A real SSL certificate checker validates 12 distinct properties: chain completeness, SAN coverage, key strength, signature algorithm, hostname match, expiry, OCSP/CRL revocation status, protocol versions enabled, cipher suite ordering, HSTS configuration, CT log inclusion, and trust path to a recognized root. Most free checkers verify 3 of those and call it a pass.
Beyond the padlock: what browsers don't show you
The Chrome padlock is a UX decision, not a technical one. Browsers actively patch over broken chains using AIA chasing: if the server forgets to send an intermediate, Chrome fetches it via the Authority Information Access extension and silently fixes the chain. Your curl won't. Your Go HTTP client won't. Your Java service definitely won't.
A green padlock means "Chrome made it work." It does not mean the cert is correctly deployed. According to SSL Labs, roughly 4-5% of public HTTPS endpoints have chain issues that browsers mask, and that number jumps significantly on internal infrastructure where nobody runs a public scanner.
The 12 checks that matter in production
A complete TLS certificate validation pass covers these 12 checks, with the CLI equivalent so you can reproduce it:
- Chain completeness:
openssl s_client -connect host:443 -showcerts - SAN coverage:
openssl x509 -in cert.pem -noout -ext subjectAltName - Key strength:
openssl x509 -in cert.pem -noout -text | grep "Public-Key" - Signature algorithm:
openssl x509 -in cert.pem -noout -text | grep "Signature Algorithm" - Hostname match:
curl --resolve host:443:1.2.3.4 https://host - Expiry:
openssl x509 -in cert.pem -noout -enddate - OCSP status:
openssl ocsp -issuer chain.pem -cert cert.pem -url <responder> - Protocol support:
nmap --script ssl-enum-ciphers -p 443 host - Cipher ordering: same nmap script, look for the server preference flag
- HSTS:
curl -sI https://host | grep -i strict-transport-security - CT log inclusion: search crt.sh for the cert's serial number
- Intermediate trust:
openssl verify -CAfile bundle.pem cert.pem
If your TLS configuration checker doesn't expose at least these 12, it's a marketing widget.
How to Check an SSL Certificate (Three Methods)
There are three honest ways to check an SSL certificate online or locally: browser DevTools for visual inspection, openssl s_client for the engineer's baseline, and automated monitoring for anything beyond a single endpoint. Each method has different blind spots. Engineering rule: if you're debugging an active incident, skip web tools. They can't reach internal endpoints behind a VPN.
Browser DevTools: quick visual inspection
Browser DevTools show the cert chain, expiry, SANs, and issuer in one click. Open DevTools → Security tab → "View certificate." It's fine for a sanity check on a public site. It's useless for SMTP STARTTLS, mTLS endpoints, or anything that isn't a GET / over HTTPS.
openssl s_client: the engineer's baseline
The openssl certificate workflow most engineers reach for:
openssl s_client -connect example.com:443 -servername example.com -showcerts < /dev/null
The -servername flag is critical. SNI-required servers will hand you the wrong cert (or a default one) without it. The < /dev/null keeps the connection from hanging on stdin.
To extract just the parts you care about:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -issuer -subject -dates -ext subjectAltName
Common gotchas in the field:
- Clock skew: a host with a drifted clock reports a perfectly valid cert as
notBeforefailed. Check NTP before the cert. - Missing intermediates: openssl shows what the server actually sent. If Chrome works but openssl complains about an unverified chain, the server is missing an intermediate and the browser fixed it for you.
- SNI mismatches: shared hosting and CDN edges hand out different certs based on the SNI hostname. Always pass
-servername.
For SMTP and other STARTTLS protocols: openssl s_client -starttls smtp -connect mx.example.com:25.
Automated monitoring: why one-off checks fail at scale
A one-off SSL certificate test answers "is this cert OK at this exact moment." It doesn't tell you the cert renewed last night but didn't actually deploy to your edge nodes. It won't catch the OCSP responder going down at 3am. We've covered the renewal-vs-deployment gap in detail; it's the failure mode that catches the most teams.
The Chain Problem Nobody Talks About
The most common silent SSL failure isn't expiry — it's an incomplete chain that browsers paper over. Chrome and Firefox implement AIA fetching, so they grab missing intermediates from the URL embedded in the cert. Most non-browser TLS stacks don't. Your cert "works fine" in QA when you test in the browser, then breaks the moment a webhook tries to POST to it.
Why your cert works in Chrome but fails in curl
Run curl -v https://example.com against a chain-broken endpoint and you'll see unable to get local issuer certificate. The cert is technically valid. The server just didn't send the intermediate, and curl doesn't go fetch it. Based on CertPulse monitoring data, roughly 7% of tracked certs have at least one TLS client that can't validate them, even though all three major browsers report green.
This is exactly the works in Chrome, breaks everywhere else class of bug. Engineers spend hours debugging "the API is down" when the API is up and the chain is broken. A proper SSL chain checker walks the chain the way a non-browser client would.
Missing intermediates and the AIA fetch gotcha
The Authority Information Access extension contains a URL pointing to the issuer's cert. Browsers follow it. Go's crypto/tls, by default, does not. Java's PKIX validator can be configured to, but isn't out of the box on older JDKs. Python's requests (via certifi) does not.
The fix is server-side: configure your web server to send the full chain, not just the leaf. For nginx, concatenate cert + intermediate(s) into the file you point ssl_certificate at. For Apache, SSLCertificateChainFile or the same concatenation trick.
Cross-signed roots and the Let's Encrypt DST transition
In September 2021, Let's Encrypt's cross-signed DST Root CA X3 expired and broke a chunk of the internet. The leaf certs were valid. The new ISRG Root X1 was already in modern trust stores. But anything running OpenSSL older than 1.1.0 (which checks expiry on every cert in the chain it builds, even if a valid path exists) blew up. We're going to see this exact pattern again as more cross-signs unwind over the next few years.
Interpreting SSL Checker Output: What Actually Matters
An SSL Labs grade A is operationally identical to A+ for 99% of use cases. The difference is HSTS preloading and a couple of cipher suite tweaks. The grade is a useful signal, but the real question is whether any warnings in the report predict an outage in the next 90 days. Most don't.
Grade A vs Grade A+: is the difference worth it?
A+ requires HSTS with max-age >= 6 months and preload submission. If you're running a public-facing consumer site, do it — the cost is one HTTP header. If you're running an internal API or a service with rotating subdomains, the preload commitment is a footgun. Once you're in the preload list, removal takes months. Plenty of teams have shipped HSTS, needed to roll it back, and learned the hard way.
Red flags that will bite you in 90 days
From incident data on certs CertPulse monitors, these warnings actually correlate with downtime:
- Expiry within 14 days with no automation: the strongest predictor of an outage we have
- OCSP stapling misconfigured on a public endpoint: triggers soft-fail in browsers, hard-fail in some compliance scanners
- Weak DH params (1024-bit) on TLS 1.2 endpoints: increasingly flagged by enterprise security scanners blocking outbound connections
- Certificate chain incomplete: ticking time bomb for any non-browser client
- SAN coverage missing a hostname users actually hit: 100% reproducible browser warning
Warnings you can safely ignore
These look scary but rarely cause real incidents:
- TLS 1.0/1.1 enabled on an internal-only endpoint with controlled clients
- "Forward secrecy not supported" on a service using only ECDHE in practice
- Lack of HPKP (Google deprecated it; don't deploy it)
- "Not in HSTS preload list" on a service that doesn't need it
Don't chase grades for their own sake. Chase the things that cause pages.
Checking Certificates at Scale
One certificate is a 30-second openssl command. 500 certificates is a systems problem requiring discovery, scheduled checks, alerting, and dedup logic. The break-even point where bash and cron stop working sits between 50 and 100 endpoints, depending on how heterogeneous your stack is. Beyond that, you need real SSL certificate monitoring infrastructure.
One cert is easy, 500 is a systems problem
The hard parts at scale: discovery (you don't know what you have), heterogeneity (ACM, Cloudflare, Let's Encrypt, Sectigo, internal CA, all reporting differently), non-443 ports (SMTP/IMAP/LDAPS), and alert dedup so you don't get 47 pages for the same wildcard. We covered the operational reality in certificate monitoring; the failure taxonomy is bigger than most teams realize.
Bash one-liner for bulk checks
A working SSL certificate expiration check across a host list:
while read -r host; do
expiry=$(echo | openssl s_client -connect "$host:443" -servername "$host" 2>/dev/null \
| openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
epoch_exp=$(date -d "$expiry" +%s 2>/dev/null)
epoch_now=$(date +%s)
days=$(( (epoch_exp - epoch_now) / 86400 ))
printf "%s\t%d days\n" "$host" "$days"
done < hosts.txt
It works. It's also blind to: STARTTLS endpoints, mTLS-required servers, wildcard-vs-SAN coverage gaps, and the renewal-deployment gap. It won't tell you about a cert that renewed in ACM but never got pushed to your CloudFront distribution.
When you've outgrown manual checking
From CertPulse monitoring data, a single platform team can manage about 50 certs with bash and calendar reminders. Past 100, you start missing things. Past 500, you're guaranteed to have shadow certificates nobody knows about. At that point you need proper SSL certificate management — not just a checker, but discovery, automation, and continuous monitoring.
Common SSL Problems an SSL Checker Will Catch
Most SSL checker tools surface the same handful of issues. The useful question isn't "what does the tool say" but "how fast can I fix it before the demo at 3pm." Here's the field guide with typical fix times:
- Expired certificate: root cause is usually a renewal job that silently failed weeks ago. Fix takes 5-30 minutes via ACME if your client is configured; up to a few hours for a manual CA-issued reissue. CT log appearance is near-instant; cache TTLs handle the rest.
- Hostname mismatch: typically a SAN missing the hostname users actually hit. Fix is a reissue with corrected SANs. ACME: 10 minutes. Commercial CA: 1-24 hours depending on validation. Watch for DNS CAA records blocking the issuer.
- Self-signed or untrusted root: either a misconfigured internal CA bundle or a cert issued by a root nobody trusts. Fix is to install the chain on clients (slow) or reissue from a public CA (fast, sometimes weeks if it's a regulated service).
- Protocol and cipher downgrades: usually a misconfigured load balancer or terminator. Fix is a config change and reload, 5-15 minutes. Watch for sticky session breakage when restarting.
- Mixed content and HSTS misconfig: mixed content is an app-side fix, sometimes hours of grep. HSTS misconfig requiring preload removal is a multi-month process.
For automated detection of expiry specifically, TLS expiry detection and renewal matters more as the 47-day certificate timeline takes effect.
SSL Checker Tools Compared
No single tool covers everything; pick based on what you're actually trying to do. Use this as a quick SSL certificate validator selection guide.
| Tool | Type | Best for | Misses |
|---|---|---|---|
| SSL Labs | Web | Public HTTPS deep audits | Internal endpoints, non-443, rate limited |
| DigiCert SSL Checker | Web | Quick expiry/chain check | Cipher detail, protocol matrix |
| SSLShopper | Web | Chain visualization | Modern protocol checks, automation |
| openssl | CLI | Engineer baseline, scriptable | High-level grading, pretty output |
| testssl.sh | CLI | Scriptable audits, all protocols | Continuous monitoring |
| sslyze | CLI | Python-friendly programmatic checks | UI for non-engineers |
| nmap ssl-enum-ciphers | CLI | Cipher enumeration | Chain validation depth |
Free web checkers are built for one-off debugging, not continuous monitoring of 200+ certificates. They rate-limit, they don't alert, they don't track changes over time, and they don't talk to internal endpoints. That's the gap CertPulse fills. CertPulse isn't trying to replace SSL Labs for ad-hoc audits; CertPulse is the thing you wire into your runbooks once you've outgrown checking by hand.
FAQ
How often should I check my SSL certificates?
Check SSL certificates continuously in production. For automated monitoring, hourly is the practical floor: any less frequent and you'll miss short-window OCSP outages and renewal-deployment gaps. For manual spot-checks during deploys, every config change to a TLS-terminating component should trigger a re-check.
Can an SSL checker detect certificate revocation?
Sometimes. OCSP queries can confirm a revocation, but most TLS clients soft-fail (treat unreachable OCSP as valid). CRLs are downloadable but stale. The only reliable revocation signal is browser distrust events combined with CT log monitoring; no single check is authoritative.
Does the checker work for internal/private certificates?
Web-based checkers can't reach internal endpoints behind a VPN or firewall. CLI tools (openssl, testssl.sh) work fine internally as long as you have network access and the trust bundle for your internal CA. For continuous monitoring of internal certs, you need an agent or a checker deployed inside your network perimeter.
Why does my certificate show valid in one tool and invalid in another?
Three usual causes: (1) different trust stores — browsers update faster than embedded systems; (2) AIA chasing — browsers fetch missing intermediates, CLI tools usually don't; (3) OCSP soft-fail behavior varies. If Chrome says valid and curl says broken, the chain is almost always incomplete server-side.
If you're using an SSL certificate checker just to verify SSL certificate status as a green/red signal, you're missing the failures that actually cause incidents. The real value is in catching chain gaps, OCSP misconfigs, and renewal-deployment misses before users do. Run the openssl commands above on your critical endpoints today, then think about what continuous monitoring looks like once you're past the manual-check threshold.
This is why we built CertPulse
CertPulse connects to your AWS, Azure, and GCP accounts, enumerates every certificate, monitors your external endpoints, and watches Certificate Transparency logs. One dashboard for every cert. Alerts when auto-renewal fails. Alerts when certs approach expiry. Alerts when someone issues a cert for your domain that you didn't request.
If you're looking for complete certificate visibility without maintaining scripts, we can get you there in about 5 minutes.