How to check an SSL certificate
Checking an SSL certificate takes under a minute. What matters is the expiry date, the hostnames it covers, whether the chain is complete — and whether the certificate you are reading is the one your server is actually serving.
There are four ways to check an SSL certificate, and they answer different questions. The browser padlock tells you whether your client trusts the certificate. The openssl command line gives you every field, including the chain. A one-line script gives you an exit code you can put in CI. And an online checker gives you an outside-in view from a network that is not yours. This guide covers all four, then explains the one mistake that makes most certificate checks lie to you.
▸ Method 1 — Check in the browser (30 seconds)
In Chrome and Edge: click the padlock (or the 'Not secure' warning) in the address bar → Connection is secure → Certificate is valid. In Firefox: click the padlock → Connection secure → More information → View Certificate, which opens a full-page view with the SAN list already expanded. In Safari: click the padlock → Show Certificate → expand Details.
This shows the issuer, the subject, and the validity window — enough to answer 'is it expired?'. It will not reliably show you the full chain as served, and it reflects your own machine's trust store, which may include corporate root CAs that public clients do not have. A certificate that looks valid on a managed work laptop can still fail for your users.
▸ Method 2 — Check with openssl (the complete view)
The full certificate, every field:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -text The -servername flag sets the SNI hostname. Without it, a server hosting several virtual hosts on one IP returns its default certificate, not yours — which is a classic way to spend an hour debugging the wrong certificate. Always pass it.
Just the expiry dates
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
| openssl x509 -noout -dates This prints notBefore and notAfter — the exact validity window the server is serving right now.
Just the hostnames it covers
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
| openssl x509 -noout -ext subjectAltNameThe full chain
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null A complete chain has the leaf certificate (your hostname), one or more intermediate CA certificates, and terminates at a root the client already trusts. The line that matters is at the end of the output: Verify return code: 0 (ok). Anything else — most commonly unable to get local issuer certificate — means an intermediate is missing. Desktop browsers often paper over this by caching intermediates from other sites, which is why a missing intermediate typically surfaces first as a failure in curl, in a mobile app, or in a server-to-server API call, not in your browser.
▸ Method 3 — Check without openssl
curl is available almost everywhere and prints the certificate during the handshake:
curl -vI https://example.com 2>&1 | grep -E 'subject:|issuer:|expire|SSL certificate'PowerShell on Windows, no extra tooling:
$r = [Net.HttpWebRequest]::Create('https://example.com')
$r.GetResponse() | Out-Null
$r.ServicePoint.Certificate.GetExpirationDateString()Python, when you want the parsed fields as data:
import ssl, socket
ctx = ssl.create_default_context()
with ctx.wrap_socket(socket.socket(), server_hostname='example.com') as s:
s.connect(('example.com', 443))
cert = s.getpeercert()
print(cert['notAfter'])▸ Method 4 — A check that fails your build
openssl x509 -checkend takes a number of seconds and sets the exit code: 0 if the certificate is still valid that far ahead, 1 if it will have expired. That makes it a one-line CI gate. Thirty days is 2592000 seconds:
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
| openssl x509 -noout -checkend 2592000 \
&& echo 'OK — more than 30 days left' \
|| echo 'WARNING — expires within 30 days'To sweep several hostnames at once — and you should, because subdomains rarely share a renewal schedule:
for h in example.com www.example.com api.example.com staging.example.com; do
printf '%-28s ' "$h"
echo | openssl s_client -servername "$h" -connect "$h:443" 2>/dev/null \
| openssl x509 -noout -enddate 2>/dev/null || echo 'UNREACHABLE'
done▸ What the fields actually mean
| FIELD | WHAT IT TELLS YOU | WHY IT BREAKS |
|---|---|---|
notAfter | Hard expiry date and time | Past it, every client refuses the connection outright |
subjectAltName | Hostnames the certificate is valid for | A wildcard *.example.com does not cover example.com itself |
Issuer | The CA that signed it | An unexpected issuer can mean a mis-issued or intercepted certificate |
Chain / Verify return code | Whether a trust path to a root exists | Missing intermediate: works in browsers, fails in curl and on mobile |
| TLS version | Protocol negotiated (1.2 / 1.3) | TLS 1.0 and 1.1 fail PCI-DSS and modern client defaults |
| Key type & signature | RSA vs ECDSA, SHA-256 | SHA-1 signatures are rejected by all current clients |
▸ The mistake that makes most checks lie
There is a difference between the certificate that was issued and the certificate that is being served. Tools that read Certificate Transparency logs or a CA dashboard tell you what was issued. That is not what your users hit.
The single most common SSL outage is not a forgotten renewal — it is a renewal that succeeded while the web server was never reloaded, so it keeps serving the old certificate from memory until it expires. Your ACME client logs success. Your CA dashboard shows a fresh certificate valid for 90 days. Certificate Transparency shows the new issuance. And port 443 still hands out the expired one. Every method in this guide avoids that trap because they all open a real TLS handshake and read what the server actually presents. Any checker that does not connect to port 443 cannot see this failure.
▸ When manual checking stops working
Manual checks are the right tool for a one-off — debugging a deploy, verifying a migration, answering 'is it me or is it them?'. They stop working as a strategy for a simple reason: they depend on someone remembering. Certificates now last 90 days by default with Let's Encrypt, and the CA/Browser Forum has voted to shorten maximum lifetimes further through 2029. The number of renewals you have to not-forget is going up, not down.
Certificate expiry monitoring replaces memory with a schedule: a probe opens the same handshake you just ran, on every hostname you own, and fires staged alerts at 30, 14, 7 and 1 day before expiry. The free SSL checker here runs a real handshake with no login if you just want the answer now — or monitor up to 10 certificates and 10 uptime endpoints free, no card. See also how to monitor SSL certificate expiration.
▸ Frequently asked questions
How do I check an SSL certificate expiry date from the command line?
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -dates. It prints notBefore and notAfter for the certificate the server is currently serving. The -servername flag is required on hosts serving multiple sites from one IP address. Why does my certificate look valid in the browser but fail in curl?
openssl s_client -connect example.com:443 -servername example.com -showcerts and check for Verify return code: 0 (ok). Fix it by configuring your server to send the full chain file rather than the leaf certificate alone. What is the difference between checking Certificate Transparency logs and checking the server?
How can I check SSL expiry in a CI pipeline?
openssl x509 -checkend <seconds>. For example echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -checkend 2592000 exits 0 when more than 30 days remain and 1 otherwise, so it fails the build on its own. Does a wildcard certificate cover the root domain?
openssl x509 -noout -ext subjectAltName. How often should SSL certificates be checked?
CertFleet probes the live certificate, watches Certificate Transparency, and alerts you 30/14/7/1 days before expiry. Free for 10 certificates, no card.