• 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

Try it: Certificate decoderOpen the full tool

Runs in your browser. Nothing you paste is sent anywhere.

PEM text, several PEM blocks, or a .pem, .crt, .cer or .der file (drop it on the box). Certificates are public, so they are safe to paste.

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

In the gameLevel 8: The certificateRoyal Notary, Keystone. In development

Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.

Last reviewed Edition 0.9