# certificate has expired

The error "certificate has expired" (OpenSSL verify error 10) means a certificate in the chain is past its `notAfter` date. Check which one before renewing: an expired intermediate invalidates everything below it while the leaf still looks fine, so renewing the leaf would change nothing. Also confirm the machine's clock is correct — a client whose date is wrong reports every valid certificate as expired, and that is a far quicker fix than a reissue.

Source: https://certguru.io/errors/certificate-has-expired/
Last updated: 2026-08-19
Commands verified against OpenSSL 3.5.7.

---

> **What it looks like**
>
> ```
>   Verify return code: 10 (certificate has expired)
>   ```
>   curl: `curl: (60) SSL certificate problem: certificate has expired`.
>   Chrome: `NET::ERR_CERT_DATE_INVALID`.

## Step 1 — check the clock first

It takes five seconds and it is a surprisingly common cause, especially on containers, virtual
machines and devices that have lost power:

```bash
date -u
```

If that is wrong, fix it and retry before touching any certificate. A client whose clock is
years ahead reports every certificate on the internet as expired.

## Step 2 — find out which certificate expired

The leaf is the obvious suspect and often not the culprit. Check every certificate the server sends:

*Dates for every certificate in the chain*

```bash
openssl s_client -connect example.com:443 -servername example.com -showcerts /dev/null \
  | awk '/BEGIN CERT/,/END CERT/' \
  | openssl storeutl -noout -text /dev/stdin 2>/dev/null \
  | grep -E "Subject:|Not After"
```

Or from files on disk:

```bash
for f in certificate.crt chain.crt; do
  echo "== $f"
  openssl x509 -in "$f" -noout -subject -enddate
done
```

> **An expired intermediate breaks everything below it**
>
> If an intermediate has expired, your leaf certificate can have months left and the site still
>   fails. Renewing the leaf changes nothing. Download the CA's current intermediate and rebuild the
>   chain file.

## Step 3 — renew

#### ACME / certbot

```bash
certbot renew --force-renewal
systemctl reload nginx
```

    If renewal is failing rather than merely overdue, run `certbot renew --dry-run` and read the
    validation error — it is usually a DNS or webroot problem rather than a certificate one. The
    [ACME challenge types](/concepts/free-tls-certificate/) explain which of the two you are looking at.

#### Manual reissue

Generate a fresh key and CSR, submit it, then rebuild the chain:

    ```bash
openssl req -new -newkey rsa:2048 -nodes \
  -keyout example.com.key -out example.com.csr \
  -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.com"
```

    ```bash
cat certificate.crt intermediate.crt > fullchain.crt
```

## Step 4 — confirm the new certificate is actually being served

Reloading is easy to forget, and a service keeps the old certificate in memory until it happens:

```bash
openssl s_client -connect example.com:443 -servername example.com /dev/null \
  | openssl x509 -noout -dates
```

If the dates are unchanged, the service did not pick up the new file — or something in front of it
(a CDN, a load balancer, a reverse proxy) is serving its own copy.

## Preventing a repeat

*Alert 30 days out, by exit code*

```bash
openssl x509 -in certificate.crt -noout -checkend 2592000 \
  || echo "WARNING: expires within 30 days"
```

Check the whole chain, not just the leaf:

```bash
for f in certificate.crt chain.crt; do
  openssl x509 -in "$f" -noout -checkend 2592000 >/dev/null \
    || echo "EXPIRING SOON: $f"
done
```

See [checking certificate expiry](/openssl/check-certificate-expiry/) for monitoring several hosts
at once.


## Frequently asked questions

### Why does the site still fail after I renewed?

Three usual reasons. The service was not reloaded, so it is still serving the old certificate from memory. An intermediate expired rather than the leaf. Or a CDN or load balancer in front holds its own copy that also needs updating.

### Can I use an expired certificate temporarily?

Only by disabling verification, which removes the protection TLS provides. There is no way to make clients accept an expired certificate. Renew it — with ACME that is one command.

### My certificate is valid but clients say expired — why?

Their clock is wrong. This is common on devices that lost power, on freshly-built virtual machines, and in containers without a time source. Fix the clock rather than the certificate.

### How do I stop this happening again?

Monitor with `-checkend` and alert well before expiry, and automate renewal. Since certificate lifetimes are shrinking, anything renewed by hand will eventually be missed.


## References

- [RFC 5280: X.509 and CRL profile](https://www.rfc-editor.org/rfc/rfc5280) — the specification every field on a certificate comes from
- [openssl-x509(1)](https://docs.openssl.org/3.5/man1/openssl-x509/) — -dates and -checkend, for confirming the diagnosis

## Related pages

- https://certguru.io/openssl/check-certificate-expiry/
- https://certguru.io/openssl/verify-certificate-chain/
- https://certguru.io/errors/curl-60-ssl-certificate-problem/
- https://certguru.io/platforms/certbot/
- https://certguru.io/concepts/certificate-chain/
- https://certguru.io/openssl/get-certificate-from-server/
- https://certguru.io/errors/unable-to-get-local-issuer-certificate/
- https://certguru.io/concepts/free-tls-certificate/

--
CertGuru — https://certguru.io
