All articles
·7 min read

How to check an SSL certificate’s expiration date (5 ways)

If you've ever watched a production site go dark because a certificate quietly hit its notAfter date, you already know why this matters. This guide shows five reliable ways to check an SSL certificate's expiration date, with exact, copy-pasteable commands. Each method is useful in a different situation, from a quick terminal one-liner to reading a cert file straight off disk.

1. openssl s_client + x509 (the terminal standard)

The most precise way to check an SSL certificate is to talk to the server directly with openssl, then pipe the certificate into openssl x509 to extract the dates. This works against any TLS endpoint, not just HTTPS.

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

Output looks like this:

notBefore=Jan  1 00:00:00 2026 GMT
notAfter=Apr  1 23:59:59 2026 GMT

The notAfter line is the expiration date. A few details worth understanding:

  • -servername is SNI (Server Name Indication). Most modern hosts serve many certificates from one IP. Without -servername, the server may hand back a default certificate that isn't the one you care about, so you'd be checking the wrong cert. Always set it to the hostname you're testing.
  • -connect host:port is the actual TCP endpoint. The hostname and port can differ from the SNI value (useful when testing a specific backend by IP).
  • echo | sends an empty line so s_client doesn't hang waiting for input. 2>/dev/null hides the verbose handshake noise.

For non-standard ports, just change them. SMTP with STARTTLS, for example:

openssl s_client -starttls smtp -servername mail.example.com \
  -connect mail.example.com:587 2>/dev/null | openssl x509 -noout -dates

Want just the day it expires, with no other output?

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

2. The browser padlock (no terminal needed)

Sometimes the fastest check is the one already in front of you. In Chrome, Firefox, or Safari, click the padlock (or the tune/site-info icon) in the address bar, then open the certificate details. Look for the Validity section with Not Before and Not After fields. The "Not After" date is your expiration.

This is great for a quick sanity check or for non-technical teammates, but it has limits: it only shows the certificate the browser negotiated for that exact hostname, and it won't help you script alerts. It's a spot check, not a monitoring strategy.

3. curl (handshake details and OCSP stapling)

curl is almost always installed, and its verbose mode prints certificate dates during the TLS handshake.

curl -vI https://example.com 2>&1 | grep -iE 'expire|start date'

You'll see lines like:

* Server certificate:
*  start date: Jan  1 00:00:00 2026 GMT
*  expire date: Apr  1 23:59:59 2026 GMT
*  subject: CN=example.com
*  issuer: C=US; O=Let's Encrypt; CN=R3

-I sends a HEAD request (no body), and -v enables verbose output so the handshake is shown. If you also want to verify the certificate's revocation status via a stapled OCSP response, use --cert-status:

curl -vI --cert-status https://example.com 2>&1 | grep -iE 'expire|OCSP'

If the server staples OCSP, curl reports the result. If it doesn't, you'll see a note that no OCSP response was received — that's not an error, just the absence of stapling.

4. An online SSL checker (zero install, checks the chain)

When you're on a machine without openssl, or you want a second opinion that also validates the full chain and SNI from outside your network, a hosted checker is the easiest option. You can check an SSL certificate with our free tool: paste a hostname and it reports the expiration date, issuer, and chain status from a neutral vantage point.

Checking from outside is genuinely useful: a certificate can look valid on the server itself while an intermediate is missing or misconfigured at the edge, which only shows up when something connects over the public internet.

5. Read a certificate file on disk

If you have the certificate file locally — common when deploying with Let's Encrypt/certbot or managing certs by hand — you don't need a network connection at all. Point openssl x509 at the file:

openssl x509 -enddate -noout -in /etc/ssl/certs/example.com.crt
notAfter=Apr  1 23:59:59 2026 GMT

This reads the PEM file directly. For certbot-managed certs, the live certificate is usually at:

openssl x509 -enddate -noout \
  -in /etc/letsencrypt/live/example.com/fullchain.pem

This is the right method for the file your server actually loads. It's worth confirming that what's on disk matches what's being served — if you renewed a cert but didn't reload the web server, the file will show the new date while the server keeps presenting the old one until you reload it. After renewing, reload your server: see the Nginx guide or the Apache guide for the exact reload command and config paths for each.

Bonus: read the issuer and SANs

Expiration is only part of the picture. You often need to confirm which hostnames a certificate actually covers (its Subject Alternative Names) and who issued it. Same tools, different flags.

Issuer and subject:

openssl x509 -noout -issuer -subject \
  -in /etc/ssl/certs/example.com.crt

Subject Alternative Names (the list of valid hostnames):

openssl x509 -noout -ext subjectAltName \
  -in /etc/ssl/certs/example.com.crt
X509v3 Subject Alternative Name:
    DNS:example.com, DNS:www.example.com

To pull SANs straight from a live server, combine method 1 with the SAN flag:

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

If the hostname you're hitting isn't in this SAN list, browsers will reject the connection even when the certificate itself hasn't expired.

Quick troubleshooting

  • s_client hangs. You forgot to feed it input. Prefix with echo | so it sends an empty line and closes.
  • You get the wrong certificate. A hosting platform served its default cert. Add -servername <host> to send the correct SNI value.
  • unable to load certificate. The file is probably DER-encoded, not PEM. Add -inform der to the openssl x509 command.
  • Dates look fine locally but clients fail. You likely renewed the cert without reloading the server, or an intermediate is missing from the served chain. Re-check from outside with method 4.
  • Already seeing failures in the browser? A cert_has_expired error means the notAfter date is in the past — see what cert_has_expired means and how to fix it.

Monitor it automatically

Checking by hand works once, but certificates expire on a schedule and humans forget. SSLNudge checks your certificates every day and emails you well before they expire, so a renewal that silently failed never turns into downtime. Sign in to start monitoring and let the daily check watch the expiry date for you.

Stop tracking expiry dates by hand

SSLNudge checks your certificates daily and alerts you before they expire.

Start free