How to Check SSL Certificate Expiry: 5 Methods
An expired SSL certificate blocks all users with a hard browser warning. Here are five ways to check certificate expiry before it becomes a problem.
ProfitTool Team
Security & Dev
Why Expiry Checks Are Not Optional Any More
An expired certificate does not degrade a site — it stops it. Browsers show a full-page interstitial, APIs throw TLS errors, and mobile apps that pin certificates fail closed. There is no partial outage and no graceful fallback.
The window for catching this is also shrinking. The CA/Browser Forum voted in 2025 to reduce the maximum lifetime of public TLS certificates in stages: 200 days from March 2026, 100 days from March 2027, and 47 days from March 2029. Annual renewal reminders in a calendar were already fragile; at 47 days they stop being viable at all. Automated issuance plus automated monitoring is the direction every public certificate is moving in.
This guide covers five ways to check expiry, from a one-off manual look to continuous monitoring.
Method 1: The Browser
Fastest for a single site. Click the padlock in the address bar, open the certificate details, and read the validity period.
| Browser | Path |
|---|---|
| Chrome / Edge | Padlock → Connection is secure → Certificate is valid |
| Firefox | Padlock → Connection secure → More information → View Certificate |
| Safari | Padlock → Show Certificate |
Two limits worth knowing. The browser shows you the certificate for the hostname you visited, not for every hostname on the server — and it shows the leaf certificate, so an expiring intermediate is easy to miss. It is a spot check, not an audit.
Method 2: OpenSSL
The tool of record. This works against any TLS service, not just HTTPS.
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -datesnotBefore=Jun 12 08:31:04 2026 GMT
notAfter=Dec 29 08:31:03 2026 GMT-servername is not optional. It sends the SNI extension. Without it, a server hosting multiple sites returns its default certificate — which may be a completely different site's — and you will confidently read the wrong expiry date. This is the most common way an OpenSSL check produces a misleading answer.
Useful variations:
# Every name the certificate covers
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -text | grep -A1 "Subject Alternative Name"
# Issuer, subject and dates together
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
# A local certificate file
openssl x509 -in /etc/ssl/certs/example.crt -noout -dates
# Non-HTTPS services
openssl s_client -connect mail.example.com:25 -starttls smtp </dev/null 2>/dev/null \
| openssl x509 -noout -datesMethod 3: A Yes/No Check for Scripts
-checkend takes a number of seconds and sets the exit status: 0 if the certificate is still valid beyond that point, 1 if it expires within it. This is what you want in monitoring, because it needs no date parsing.
# Will it still be valid in 30 days? 30 * 86400 = 2592000
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -checkend 2592000
echo $? # 0 = fine, 1 = expires within 30 daysA complete check script:
#!/usr/bin/env bash
set -uo pipefail
THRESHOLD_DAYS=${THRESHOLD_DAYS:-30}
SECONDS_AHEAD=$((THRESHOLD_DAYS * 86400))
STATUS=0
for host in "$@"; do
cert=$(echo | openssl s_client -connect "${host}:443" -servername "$host" 2>/dev/null \
| openssl x509 2>/dev/null)
if [ -z "$cert" ]; then
echo "ERROR $host — could not retrieve certificate"
STATUS=1
continue
fi
expiry=$(echo "$cert" | openssl x509 -noout -enddate | cut -d= -f2)
if echo "$cert" | openssl x509 -noout -checkend "$SECONDS_AHEAD" >/dev/null; then
echo "OK $host — expires $expiry"
else
echo "EXPIRING $host — expires $expiry (within ${THRESHOLD_DAYS} days)"
STATUS=1
fi
done
exit $STATUS$ ./check-certs.sh example.com api.example.com
OK example.com — expires Dec 29 08:31:03 2026 GMT
EXPIRING api.example.com — expires Sep 30 11:02:44 2026 GMT (within 30 days)The non-zero exit makes it usable directly as a cron job, a CI step, or a Nagios-style check.
Portability note. Many published versions of this script convert the date withdate -d, which is GNU-specific and fails on macOS and BSD, where the equivalent isdate -j -f. Using-checkendavoids date parsing entirely, so the script above runs unchanged on Linux and macOS.
Method 4: Check the Whole Chain, Not Just the Leaf
Your certificate can be perfectly valid while the site still breaks, because an intermediate certificate in the chain has expired. The leaf is what everyone monitors; the intermediate is what nobody does. It has caused several well-publicised outages.
# Expiry date of every certificate the server presents
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
| awk '/BEGIN CERT/,/END CERT/' \
| openssl storeutl -noout -text /dev/stdin 2>/dev/null \
| grep -E "Subject:|Not After"Also confirm the chain actually verifies, which catches a missing intermediate as well as an expired one:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>&1 \
| grep -E "Verify return code|verify error"Verify return code: 0 (ok) is what you want. A missing intermediate often works in desktop Chrome — which can fetch it — while failing in mobile apps and curl, which is why "it works on my machine" is a poor test here.
Method 5: Continuous Monitoring
Manual checks catch what you remember to check. Renewal fails on the host nobody thought about.
| Approach | How it works | Suits |
|---|---|---|
| Cron + the script above | Runs daily, emails or posts on non-zero exit | Small estates, no extra infrastructure |
| Prometheus blackbox exporter | Exposes probe_ssl_earliest_cert_expiry; alert on the remaining time | Teams already running Prometheus |
| Uptime monitoring services | Most bundle certificate expiry alerts with uptime checks | Teams already paying for uptime monitoring |
| Certificate Transparency feeds | Watch CT logs for issuance on your domains | Detecting unexpected or unauthorised issuance |
A Prometheus alert rule:
- alert: CertificateExpiringSoon
expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 21
for: 1h
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} certificate expires in {{ $value | printf \"%.0f\" }} days"Note that probe_ssl_earliest_cert_expiry reports the earliest expiry in the chain, so it covers the intermediate problem from Method 4 automatically.
Choosing an Alert Threshold
The threshold should be set by how long a manual recovery takes, not by habit.
| Certificate lifetime | Suggested first alert | Reasoning |
|---|---|---|
| 90 days (Let's Encrypt) | 21 days | Certbot attempts renewal at 30 days remaining; alerting at 21 means several automated attempts have already failed |
| 200 days (current CA/B maximum) | 30 days | Enough room for a manual reissue and a change window |
| Internal / private PKI | 30–45 days | Internal processes are usually slower and less automated |
The principle for automated renewal: alert after automation should have succeeded, not before. Alerting at 45 days on a Let's Encrypt certificate fires while renewal is still working normally, and an alert that is usually noise is an alert people stop reading.
Automate Renewal, Then Monitor It
Monitoring tells you renewal failed. Automation is what stops it failing.
# Certbot: what is installed and when it expires
sudo certbot certificates
# Test renewal without hitting rate limits
sudo certbot renew --dry-run
# Is the renewal timer actually running?
systemctl list-timers | grep certbotCertbot's renew only acts on certificates within 30 days of expiry, so a renew that reports "not yet due" is success, not failure. The --dry-run is the meaningful test.
The failure worth planning for is not renewal itself but deployment: a certificate that renews on disk while the running service keeps serving the old one from memory. Whatever reloads nginx, HAProxy, or your application must run as a deploy hook after every successful renewal, and it must be tested — a renewal that never reaches the listening socket looks fine in certbot certificates and expires in production.
Common Mistakes
- Omitting
-servername. Returns the wrong certificate on any shared or multi-tenant host. - Monitoring the CDN, not the origin. If the CDN terminates TLS, its certificate is the one you see. The origin's certificate expires independently and takes the site down just as effectively.
- Monitoring only the apex.
api.,admin.,staging.and internal service endpoints have their own certificates and their own renewal paths. - Relying on the CA's expiry emails. They go to whatever address was on file at issuance — often someone who has left.
- Assuming automation works because it was set up. Renewal breaks on credential rotation, DNS provider migrations, and firewall changes.
--dry-runon a schedule is the only proof. - Ignoring non-HTTPS services. SMTP, IMAP, LDAP and database TLS certificates expire on the same clock and are monitored far less often.
Frequently Asked Questions
What happens the moment a certificate expires? Clients reject the connection outright. Browsers show an interstitial the user can sometimes click through; APIs, mobile apps and server-to-server calls generally cannot, so integrations break before anyone reports a website problem.
Can I still check expiry if the site is already down? Yes, if the server still completes a TLS handshake — openssl s_client reports the dates regardless of whether the certificate is valid. If the service is fully down, check the certificate file directly on the host with openssl x509 -in <file> -noout -dates.
Does renewing early waste the remaining time? No. CAs issue a new certificate with a full validity period from the issuance date; you are not charged the unused remainder. Renewing at 30 days remaining loses nothing.
Why does one browser complain when another does not? Almost always a missing or expired intermediate. Browsers differ in whether they fetch the missing certificate themselves, so serving the complete chain from your server is the fix.
Check expiry dates, the full chain, and every covered hostname for any domain with the SSL Certificate Checker. If a wildcard certificate is not covering the host you expected, What Is a Wildcard SSL Certificate? explains the matching rules — and the DNS Lookup tool will confirm an ACME DNS-01 record has propagated before a renewal run.
ProfitTool Team
Security & DevWritten and maintained by the ProfitTool team. Where an article references a ProfitTool utility, the behaviour described is the behaviour of the tool on this site — you can open it and check the output yourself.
Try the Interactive Tools Mentioned
Free to use with no ProfitTool signup. Data handling varies by tool.
More from the Knowledge Hub
What Is a Wildcard SSL Certificate?
A wildcard SSL certificate secures a domain and all its direct subdomains with one certificate. How they work, why they stop at one level, and when to use one.
Privacy & SecuritySSL vs TLS: What Is the Difference?
SSL and TLS are both protocols for encrypting internet connections, but they are not the same. This guide explains the history, the differences, and why only TLS should be used today.
Privacy & SecurityWhat Is an SSL Certificate and How Does It Work?
SSL certificates authenticate websites and encrypt data in transit. This guide explains what a certificate contains, how TLS handshakes work, and what to check before your certificate expires.