Check when a certificate expires

To read a certificate's expiry date, run `openssl x509 -in certificate.crt -noout -enddate`. For a live server, pipe `s_client` into `x509`: `openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -enddate`. In monitoring, use `-checkend` instead of parsing dates — `openssl x509 -in certificate.crt -noout -checkend 2592000` exits 0 if the certificate is still valid 30 days from now and 1 if it is not, which is exactly what a check script needs.

Updated August 19, 2026 Verified against OpenSSL 3.5.7

From a file #

Expiry date only
openssl x509 -in certificate.crt -noout -enddate
Expected output
notAfter=Nov 14 23:59:59 2026 GMT
Both ends of the validity window
openssl x509 -in certificate.crt -noout -dates
Expected output
notBefore=Aug 16 00:00:00 2026 GMT
notAfter=Nov 14 23:59:59 2026 GMT

From a live server #

What the server is actually serving right now
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -enddate
Expected output
notAfter=Nov 14 23:59:59 2026 GMT

The form you want in monitoring #

Parsing and comparing dates in shell is fiddly and locale-sensitive. -checkend does the comparison for you and answers with an exit code:

Is it still valid 30 days from now?
openssl x509 -in certificate.crt -noout -checkend 2592000
Expected output
Certificate will not expire
Branch on the exit code
if openssl x509 -in certificate.crt -noout -checkend 2592000; then
echo "OK — more than 30 days left"
else
echo "WARNING — expires within 30 days"
fi
Seconds Window
0 Expired right now
604800 7 days
2592000 30 days
5184000 60 days
7776000 90 days

Checking a live server in a script #

Exit non-zero if a host's certificate expires within 30 days
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -checkend 2592000

Wrapped into something you can run over a list of hosts:

Check several hosts at once
for host in example.com api.example.com www.example.com; do
if openssl s_client -connect "$host:443" -servername "$host" </dev/null 2>/dev/null \
   | openssl x509 -noout -checkend 2592000 >/dev/null; then
  echo "OK       $host"
else
  echo "EXPIRING $host"
fi
done

Days remaining as a number #

Useful when feeding a metrics system rather than an alert:

Print days until expiry
end=$(openssl x509 -in certificate.crt -noout -enddate | cut -d= -f2)
echo $(( ( $(date -d "$end" +%s) - $(date +%s) ) / 86400 ))

Do not forget the chain #

A leaf certificate with plenty of time left is still broken if an intermediate above it has expired, and checking only the leaf will not show it:

Check every certificate in a bundle
openssl crl2pkcs7 -nocrl -certfile fullchain.crt \
| openssl pkcs7 -print_certs \
| openssl x509 -noout -subject -enddate 2>/dev/null

See verify a certificate chain.

Frequently asked questions

What does -checkend return?
An exit code, not a date. It exits 0 if the certificate is still valid the given number of seconds from now, and 1 if it will have expired. It also prints a line of text, but the exit code is what a script should branch on.
How do I check expiry without OpenSSL?
On a live server you can use curl -vI https://example.com and read the certificate lines, or echo | openssl s_client if OpenSSL is present but you dislike the syntax. There is no reliable way to read a certificate file's dates without a tool that parses ASN.1.
Why does my certificate look valid but browsers say it is not?
Check the notBefore date as well as notAfter, and check the whole chain — an expired intermediate invalidates everything below it while the leaf still looks fine. See verifying a chain.
What time zone are the dates in?
Always GMT/UTC. X.509 requires it, and OpenSSL prints the GMT suffix to make that explicit.

References