A browser says the certificate has expired, or a monitor says it's about to. Before you touch anything, ask the server what it's really presenting. That takes one command, and most of the mistakes come from looking at the wrong certificate.
The command
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=Sep 26 22:49:11 2026 GMT notAfter=Dec 25 22:56:35 2026 GMT The first openssl connects and prints the handshake, and the second reads the certificate out of it. echo | closes the connection instead of leaving it waiting for your input. notAfter in the past means expired. notBefore in the future means not valid yet, and the same browser error covers both.
Don't drop -servername
One address can serve many sites, and -servername says which one you want. I set up a throwaway nginx with three sites on one port and asked for two of them, then for none:
echo | openssl s_client -connect 127.0.0.1:18443 -servername old.test 2>/dev/null \ | openssl x509 -noout -subject -enddate subject=CN=old.test notAfter=Jan 1 00:00:00 2025 GMT With -servername good.test the same port gave:
subject=CN=good.test notAfter=Jan 1 00:00:00 2030 GMT And with -noservername, I got the default site's certificate, which was neither of those:
subject=CN=future.test So if you leave the name out, or get it wrong, the dates you read may belong to some other site on that server.
A check you can script
-checkend takes a number of seconds and exits non-zero if the certificate will have expired by then. 2592000 is 30 days.
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \ | openssl x509 -noout -checkend 2592000 echo "exit=$?" Certificate will not expire exit=0 Widened to 90 days (7776000), the same certificate says:
Certificate will expire exit=1 There's a catch. It only looks at the end date. My test certificate that doesn't start until 2030 said this:
subject=CN=future.test notBefore=Jan 1 00:00:00 2030 GMT notAfter=Jan 1 00:00:00 2031 GMT Certificate will not expire exit=0 A browser would refuse that certificate. So a passing -checkend doesn't prove it's valid today. Also, if the connection fails, openssl x509 finds nothing to read and exits 1 with Could not find certificate from <stdin>. So in a script, exit 1 can mean "expiring" or "couldn't connect". Read the message as well as the status.
Does it cover the name you're using?
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 The dates can be fine and the name still wrong. That's a different browser error.
Renewed, but still the old date?
If your renewal tool shows a new date and this command doesn't, check two things.
The server hasn't loaded the new file. I overwrote the certificate files on that test nginx, and the command kept showing the old one:
subject=CN=old.test notAfter=Jan 1 00:00:00 2025 GMT After nginx -s reload:
subject=CN=good.test notAfter=Jan 1 00:00:00 2030 GMT You're reaching a different machine. If a CDN sits in front, you're reading the CDN's certificate. To read your own server's, connect to its IP and keep your domain as the name:
echo | openssl s_client -connect YOUR.SERVER.IP:443 -servername yourdomain.com 2>/dev/null \ | openssl x509 -noout -dates I only tested that form against a local nginx at 127.0.0.1. Untested against a real CDN and origin. A firewall that lets only your CDN in will block this from outside, so you'd run it on the server itself.
What I ran it on
OpenSSL 3.6.3 on macOS, on 3 November 2026, and again on 5 November 2026 with the same results. The local tests used nginx 1.30.6 in Docker, with self-signed certificates made for the purpose. The example.com output is from those days, and its dates will have changed by the time you read this. Untested: other OpenSSL versions and LibreSSL.
An AI agent wrote this post and ran every command above on 3 and 5 November 2026; I chose the topic and approved it for posting. I run SiteHealthRadar. A longer version covering hosting panels, Cloudflare and Certbot is at https://sitehealthradar.com/guides/err-cert-date-invalid/.

