- OpenSSL
- Exact text checked with the real tool
verify error:num=10:certificate has expired
Also seen in: curl, git, Python, Node.js (CERT_HAS_EXPIRED), npm
In one sentence
A certificate in the chain is past its notAfter date: usually the server's certificate was not renewed or the renewed one never loaded; sometimes the client's clock is wrong.
Where you see it
In openssl s_client output, and in every tool built on OpenSSL. The code is X509_V_ERR_CERT_HAS_EXPIRED in the OpenSSL verification options documentation.
$ openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null
Connecting to 192.0.2.30
CONNECTED(000001C4)
depth=2 O=Example CA, CN=Example Root CA
verify return:1
depth=1 O=Example CA, CN=Example Issuing CA
verify return:1
depth=0 CN=www.example.com
verify error:num=10:certificate has expired
notAfter=Apr 1 00:00:00 2026 GMT
verify return:1
...
Verification error: certificate has expired
Verify return code: 10 (certificate has expired)
Other tools show the same text: curl and git print SSL certificate problem: certificate has expired, Python prints certificate verify failed: certificate has expired, and Node.js and npm report CERT_HAS_EXPIRED.
What it means
Every certificate has a validity period: a notBefore and a notAfter date. Clients compare those dates with their own clock. At the depth shown (depth=0 is the server’s own certificate, depth=1 the intermediate above it), the current time is past notAfter, so the certificate can no longer be relied on, even if everything else is correct.
Likely causes
The server’s certificate expired
Confirm what the server is serving right now:
openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -dates
subject=CN=www.example.com
notBefore=Jan 1 00:00:00 2026 GMT
notAfter=Apr 1 00:00:00 2026 GMT
Fix: renew the certificate with your CA or ACME client, install it with its full chain, and reload the server. With certbot and nginx, for example:
sudo certbot renew
sudo nginx -t && sudo systemctl reload nginx
It was renewed, but the server still serves the old one
Common after a manual renewal or a failed reload hook. Compare the file on disk with what the server sends:
openssl x509 -in /etc/ssl/www.example.com/fullchain.pem -noout -enddate
If the file is newer than what s_client shows, reload or restart the service. Behind a load balancer, test each backend directly, because one node may still have the old certificate:
openssl s_client -connect 192.0.2.31:443 -servername www.example.com </dev/null 2>/dev/null | openssl x509 -noout -enddate
Also check where TLS actually ends: a load balancer, CDN or ingress controller may hold its own copy of the certificate.
An intermediate in the chain expired
If the error shows depth=1 or higher, the server’s certificate is fine but it is sent with an outdated intermediate. Download the current chain from your CA, rebuild fullchain.pem (server certificate first), and reload.
The client’s clock is wrong
If a certificate that is valid elsewhere fails on one machine, check that machine’s time in UTC:
date -u
timedatectl status
w32tm /query /status
Turn on time synchronisation (sudo timedatectl set-ntp true on systemd Linux, w32tm /resync on Windows). A clock that runs behind gives the opposite error: verify error:num=9:certificate is not yet valid.
An old client builds an outdated path
Very old OpenSSL versions and stale CA bundles can pick a path through an expired root or cross-signed certificate even when a valid path exists. Update the CA bundle and the TLS library on the client.
Lifetimes are getting shorter: public TLS certificates may be valid for at most 200 days since 15 March 2026, and for at most 47 days from 15 March 2029. Manual renewal will not keep up, so automate it, for example with ACME, and monitor what each endpoint actually serves.
Check yours
Paste the server’s certificate (the first BEGIN CERTIFICATE block from openssl s_client -showcerts). The decoder shows notBefore, notAfter and how many days are left or overdue.
Learn why
- Anatomy of an X.509 certificate: the validity fields.
- Inventory, expiry and renewal: how to stop expiry outages.
- ACME and the 47-day schedule: automated renewal.
- Browser version of this error: NET::ERR_CERT_DATE_INVALID.
- See also: the same problem in Node.js, Java and Go and kubectl.
Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.