There are three ways to check an SSL certificate's expiry date, and they don't all show you the same thing. The distinction matters: a certificate can exist on disk with months left while the server serves a different one that's about to expire.
Here's each method, what it actually checks, and when to use it.
Method 1: Browser (Fastest for a Quick Check)
Click the padlock icon in your browser's address bar. In Chrome and Edge, choose "Connection is secure" then "Certificate is valid." In Firefox, choose "Connection secure" then "More information" then "View Certificate."
The certificate panel shows the issuer, subject domains, and validity period. The "Not valid after" or "Expires" field is the expiry date.
What this checks: the certificate your browser session received from the server. For a single domain you can visit, this is a fast sanity check.
Limitations: it only works for domains you can open in a browser, and it shows what that one browser received — not necessarily what other clients, regions, or Cloudflare see. Also, different browsers cache differently, so a recently renewed certificate may not show in all sessions immediately.
Method 2: openssl Command Line (Most Accurate)
The openssl command performs a live TLS handshake and returns the certificate the server is actively serving:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null 2>/dev/null \
| openssl x509 -noout -datesOutput looks like this:
notBefore=Jan 1 00:00:00 2026 GMT
notAfter=Oct 1 00:00:00 2026 GMTThe notAfter line is the expiry. The -servername flag is required — without it, a server hosting multiple certificates (SNI) may return the wrong one for your domain.
For a one-liner that returns just the expiry date:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null 2>/dev/null \
| openssl x509 -noout -enddateWhy this matters more than checking files on disk: if a certificate renewed but the server was never reloaded, the cert file on disk shows a future expiry date — everything looks fine. The openssl command shows what's actually being served over the wire. So does Cloudflare. So does every visitor's browser. A mismatch between the two is exactly the condition that produces a Cloudflare 526 error.
Every openssl Command for Certificate Expiry
The handshake above checks a live server. Often you need the expiry date of a certificate file sitting on disk instead — after downloading a bundle from a CA, or when auditing a server you're already logged into.
For a PEM file, read the expiry directly:
openssl x509 -enddate -noout -in certificate.pemFor a Let's Encrypt certificate, the file you want is the full chain in the live directory:
openssl x509 -enddate -noout -in /etc/letsencrypt/live/yourdomain.com/fullchain.pemBinary DER certificates — usually named .crt or .der — need an explicit input format, or openssl fails with an unable to load certificate error:
openssl x509 -enddate -noout -inform der -in certificate.crtTo see the full validity window rather than just the end date, swap -enddate for -dates. To see everything the certificate contains — issuer, subject alternative names, key usage — use -text:
openssl x509 -noout -text -in certificate.pemFor scripting, -checkend is more useful than a date string. It takes a number of seconds and exits 0 if the certificate is still valid that far ahead, or 1 if it will have expired by then:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null 2>/dev/null \
| openssl x509 -noout -checkend 25920002592000 seconds is 30 days. The answer is the exit code rather than the output, so use it in a conditional instead of reading what it prints.
Mail servers need a different invocation. Certificates on SMTP, IMAP, and POP3 ports are negotiated after the connection opens, so s_client has to be told which protocol to speak first:
openssl s_client -connect mail.yourdomain.com:587 -starttls smtp < /dev/null 2>/dev/null \
| openssl x509 -noout -enddateSubstitute -starttls imap for port 143 or -starttls pop3 for port 110. Ports 465 and 993 are implicit TLS and take the plain form with no -starttls flag.
Method 3: Online Tool (No Terminal Required)
If you don't have terminal access, or you're checking a domain on infrastructure you don't own, an online SSL checker runs the same TLS handshake from an external network and returns the expiry date.
The ExpiryPing SSL checker checks the live certificate on any public hostname — enter the domain, get the expiry date and days remaining. No account required.
The external check is also worth running even when you do have terminal access. It confirms what visitors and Cloudflare see from outside your network — catching the renewed-but-not-reloaded case that an on-server openssl check would miss.
Checking a certificate expiry date online is also the only practical option when the domain isn't yours — a vendor's API endpoint, a partner's portal, a service you're evaluating. You don't need access to the server, only the hostname, because the certificate is presented to anyone who opens a connection.
Check SSL Certificate Expiration Date on Linux
The openssl commands above work on every Linux distribution, but the paths don't. Debian and Ubuntu keep the system trust store in /etc/ssl/certs, while RHEL, Fedora, and Amazon Linux use /etc/pki/tls/certs. Certificates you installed yourself live wherever your web server config points — read the ssl_certificate directive in nginx or SSLCertificateFile in Apache rather than guessing.
If certbot manages the certificate, it reports the expiry for everything it knows about in one command:
sudo certbot certificatesThe output lists each certificate name, its domains, and an expiry date with the days remaining already calculated. This reads certbot's own records, though — it reports what was issued, not what the server is currently serving. If nginx was never reloaded after the last renewal, certbot shows a healthy future date while visitors get an expired certificate.
To check several domains in one pass:
for d in example.com api.example.com mail.example.com; do
echo -n "$d: "
openssl s_client -connect $d:443 -servername $d < /dev/null 2>/dev/null \
| openssl x509 -noout -enddate
doneThat's a spot check across a list, not monitoring — it tells you where things stand at the moment you run it, and nothing about next month.
Check Certificate Expiry on Windows (Including .pfx Files)
Windows Server keeps certificates in the certificate store rather than as files on disk, and PowerShell reads it directly. To list every certificate in the machine's personal store with its expiry date:
Get-ChildItem Cert:\LocalMachine\My | Select-Object Subject, NotAfter, ThumbprintThe NotAfter property is the expiry — the same field openssl prints as notAfter. To narrow that to certificates expiring within the next 30 days:
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.NotAfter -lt (Get-Date).AddDays(30) }For a .pfx file, which bundles the certificate and its private key into one password-protected container, read the expiry without importing anything:
Get-PfxCertificate -FilePath C:\certs\yourdomain.pfx | Select-Object Subject, NotBefore, NotAfterPowerShell prompts for the password if the file has one. To supply it non-interactively, construct the certificate object directly:
$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\certs\yourdomain.pfx", "password")
$pfx.NotAfterIf openssl is installed on the machine, it reads .pfx files too — useful in a mixed environment where you want the same command everywhere:
openssl pkcs12 -in yourdomain.pfx -nokeys -passin pass:yourpassword | openssl x509 -noout -enddateEverything above reads certificates at rest. To check what a Windows server is actually serving over the wire, without installing openssl, open a connection and inspect the certificate the remote host presents:
$req = [Net.HttpWebRequest]::Create("https://yourdomain.com")
$req.GetResponse().Dispose()
$req.ServicePoint.Certificate.GetExpirationDateString()That's the Windows equivalent of the openssl handshake — it reports the served certificate, not the stored one, which is the distinction that matters after a renewal.
Certificate Validity vs Certificate Expiry
"Is this certificate valid?" and "when does this certificate expire?" are different questions, and a certificate can pass one while failing the other. Expiry is a single field: a date the certificate can't be used past. Validity is everything at once — the certificate is inside its date window, the hostname matches, the signature chain leads to a trusted root, and it hasn't been revoked.
A certificate with eight months left is still invalid if it was issued for www.yourdomain.com and you're serving it on yourdomain.com, or if the intermediate certificate is missing from the chain your server sends.
The s_client output shown earlier already answers the validity question — the verification result is printed near the end of the handshake:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null 2>/dev/null \
| grep -E "Verify return code|subject="Verify return code: 0 (ok) means the full chain verified. Anything else is a validity failure with the reason attached: unable to get local issuer certificate is a missing intermediate, and certificate has expired is the one this article is about.
To verify a certificate file against its chain with no network connection involved:
openssl verify -untrusted intermediate.pem certificate.pemChecking expiry tells you when a working certificate will stop working. Checking validity tells you whether it works right now.
What "Days Remaining" Actually Means
Most tools show days remaining alongside the raw expiry date. The calculation uses UTC, not local time. A certificate that expires at midnight UTC on July 1st is already expired in UTC at 11:59 PM local time on June 30th in any timezone west of UTC.
This matters when a countdown shows "1 day remaining" and you're cutting it close.
Checking Multiple Domains
The methods above work for spot checks. For ongoing visibility across more than a handful of domains, manual checks don't hold up — you'd need to remember to run them regularly, and you need lead time, not just a current reading.
ExpiryPing runs the same external TLS check daily for every domain you add and sends alerts at 30, 14, 7, and 1 day before expiry. Email and Slack. No credentials, no server access, no agent to install — it only needs the hostname, same as the openssl command.
Free for up to 3 domains. Paid plans from $19/month for up to 10.
A one-time check tells you where things stand today. Monitoring tells you before the next expiry becomes a problem.