Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for DevOps Security & Hardening By James Joyner IV · · 9 min read

TLS & Security Error Guide: 'x509: certificate has expired or is not yet valid'

Fix the x509 certificate expired/not-yet-valid TLS error: check notBefore/notAfter dates, clock skew, intermediate expiry, and renew or replace the cert chain.

  • #security
  • #troubleshooting
  • #errors
  • #tls

Overview

This error means a TLS client validated the server’s certificate chain and rejected it because the current time falls outside the certificate’s validity window. Every X.509 certificate carries a notBefore and notAfter timestamp; if “now” is before notBefore or after notAfter, verification fails. The same message appears when an intermediate or root in the chain has expired, even if the leaf is still valid.

You will see it from Go-based clients (Docker, kubectl, Vault, etcd, Prometheus):

x509: certificate has expired or is not yet valid: current time 2026-06-23T14:02:11Z is after 2026-06-01T00:00:00Z

Or from a generic TLS stack as certificate verify failed (certificate has expired). The failure is time-relative, so a cert that works on one host can fail on another whose clock is wrong, and a chain that was fine yesterday can break overnight when an intermediate lapses.

Symptoms

  • TLS clients abort with “certificate has expired or is not yet valid”.
  • Browsers show NET::ERR_CERT_DATE_INVALID.
  • Services that were healthy fail at a date boundary (often midnight UTC).
  • Newly issued certs fail with “is not yet valid” on a host whose clock is behind.
echo | openssl s_client -connect api.internal.example.com:443 -servername api.internal.example.com 2>/dev/null \
  | openssl x509 -noout -dates
notBefore=Jun  1 00:00:00 2025 GMT
notAfter=Jun  1 00:00:00 2026 GMT
date -u
Mon Jun 23 14:02:11 UTC 2026

The current time is well past notAfter — the leaf has expired.

Common Root Causes

1. The leaf certificate has simply expired

The most common case: nobody renewed it. Check the dates directly against the live endpoint.

echo | openssl s_client -connect api.internal.example.com:443 2>/dev/null \
  | openssl x509 -noout -enddate
notAfter=Jun  1 00:00:00 2026 GMT

If notAfter is in the past, the leaf must be renewed.

2. An intermediate (or root) in the chain has expired

The leaf can be valid while an intermediate CA has lapsed. Inspect every cert the server presents, not just the first.

echo | openssl s_client -connect api.internal.example.com:443 -showcerts 2>/dev/null \
  | awk '/-----BEGIN/,/-----END/' \
  | openssl storeutl -noout -text -certs /dev/stdin 2>/dev/null \
  | grep -E 'Subject:|Not After'
        Not After : Jun  1 00:00:00 2026 GMT
        Subject: CN = Example Intermediate CA R3
        Not After : Apr 30 00:00:00 2026 GMT

The intermediate Not After is in the past — the whole chain is rejected.

3. Host clock skew (cert “is not yet valid”)

A freshly issued cert with a notBefore slightly in the future, plus a host clock that is behind, produces “is not yet valid”.

timedatectl status | grep -E 'System clock|NTP|synchronized'
           System clock synchronized: no
                         NTP service: inactive

An unsynchronized clock that is days behind will reject valid certs.

4. A pinned/cached CA bundle that no longer matches

Long-running processes cache the system CA bundle at start. If a root was rotated, the in-memory copy may still reference an expired anchor.

openssl x509 -in /etc/ssl/certs/ca-certificates.crt -noout -enddate 2>/dev/null
ls -l --time-style=+%Y-%m-%d /etc/ssl/certs/ca-certificates.crt
notAfter=Sep 30 14:01:15 2026 GMT
-rw-r--r-- 1 root root 215000 2025-02-10 /etc/ssl/certs/ca-certificates.crt

A stale bundle file (old modify date) often lags behind a CA rotation.

5. Wrong certificate served for the SNI / vhost

A reverse proxy with multiple vhosts may serve a default (expired) cert when SNI is missing or mismatched.

echo | openssl s_client -connect 10.0.0.5:443 2>/dev/null | openssl x509 -noout -subject -enddate
echo | openssl s_client -connect 10.0.0.5:443 -servername api.internal.example.com 2>/dev/null \
  | openssl x509 -noout -subject -enddate
subject=CN = default.invalid
notAfter=Jan  1 00:00:00 2024 GMT
subject=CN = api.internal.example.com
notAfter=Aug 15 00:00:00 2026 GMT

Without SNI the proxy returns the expired default cert.

6. Automated renewal (ACME / cert-manager) silently stopped

The renewal job exists but failed; the on-disk cert never updated.

sudo certbot certificates 2>/dev/null | grep -E 'Certificate Name|Expiry Date'
sudo systemctl list-timers certbot.timer --no-pager
  Certificate Name: api.internal.example.com
    Expiry Date: 2026-06-01 00:00:00+00:00 (INVALID: EXPIRED)

INVALID: EXPIRED plus a timer that has not run recently points to a broken renewal hook.

Diagnostic Workflow

Step 1: Confirm which cert and which boundary failed

echo | openssl s_client -connect <HOST>:<PORT> -servername <HOST> 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

Compare notBefore/notAfter against the current UTC time.

Step 2: Verify the host clock

date -u
timedatectl status | grep -E 'synchronized|NTP'

If the clock is wrong, fix NTP first — it may be the entire problem (especially for “is not yet valid”).

Step 3: Inspect the full chain, not just the leaf

echo | openssl s_client -connect <HOST>:<PORT> -servername <HOST> -showcerts 2>/dev/null \
  | grep -E 'depth|verify|Not After' 
echo | openssl s_client -connect <HOST>:<PORT> -servername <HOST> 2>/dev/null \
  | grep -E 'Verify return code'

Verify return code: 10 (certificate has expired) tells you the chain (not just the leaf) is the issue.

Step 4: Locate the on-disk cert and renewal state

sudo certbot certificates 2>/dev/null | grep -E 'Certificate Name|Expiry|Path'
# or for cert-manager
kubectl get certificate -A -o wide
kubectl describe certificate <NAME> -n <NS> | grep -E 'Not After|Renewal|Message'

Step 5: Renew/replace and reload

sudo certbot renew --force-renewal --cert-name <HOST>
sudo systemctl reload nginx
# verify the new dates are served
echo | openssl s_client -connect <HOST>:443 -servername <HOST> 2>/dev/null \
  | openssl x509 -noout -enddate

Example Root Cause Analysis

A Prometheus scrape of an internal exporter starts failing at 00:00 UTC:

x509: certificate has expired or is not yet valid: current time 2026-06-01T00:14:03Z is after 2026-06-01T00:00:00Z

The leaf served by the exporter still shows a 2027 notAfter, so the leaf is fine. Dumping the full chain reveals the culprit:

echo | openssl s_client -connect exporter.internal:9100 -showcerts 2>/dev/null \
  | openssl storeutl -noout -text -certs /dev/stdin 2>/dev/null \
  | grep -E 'Subject:|Not After'
        Not After : Mar 14 00:00:00 2027 GMT
        Subject: CN = Internal Issuing CA
        Not After : Jun  1 00:00:00 2026 GMT

The intermediate Internal Issuing CA expired at exactly the boundary that broke the scrape. The leaf was reissued months ago but the bundle stapled to it still chains through the old, now-expired intermediate.

Fix: reissue the leaf so it ships the new intermediate, update the server’s fullchain file, and reload:

# replace the bundled intermediate with the current one, then:
cat leaf.pem new-intermediate.pem > /etc/exporter/fullchain.pem
sudo systemctl reload node_exporter
echo | openssl s_client -connect exporter.internal:9100 2>/dev/null | grep 'Verify return code'
    Verify return code: 0 (ok)

The chain now validates and scrapes recover.

Prevention Best Practices

  • Monitor expiry on the leaf and every intermediate, not just the leaf. Alert at 30 and 7 days remaining with openssl x509 -checkend.
  • Keep NTP enabled and synchronized on every host; clock drift causes both “expired” and “not yet valid” false failures.
  • Automate renewal (ACME/cert-manager) and alert when a renewal timer fails or skips — a silent renewal failure is the top cause of surprise expiry.
  • Always serve the full chain (fullchain.pem), and re-verify the served chain after any CA rotation.
  • Treat CA/intermediate rotation as a scheduled change with a re-issue of dependent leaves; see the security hardening guides for a rotation checklist.
  • For fast triage of an overnight TLS outage, the free incident assistant can map an x509 expiry message to the specific cert in the chain that lapsed.

Quick Command Reference

# Dates on the served leaf
echo | openssl s_client -connect <HOST>:443 -servername <HOST> 2>/dev/null | openssl x509 -noout -dates

# Full chain expiry (every cert presented)
echo | openssl s_client -connect <HOST>:443 -showcerts 2>/dev/null \
  | openssl storeutl -noout -text -certs /dev/stdin 2>/dev/null | grep -E 'Subject:|Not After'

# Chain verify result
echo | openssl s_client -connect <HOST>:443 -servername <HOST> 2>/dev/null | grep 'Verify return code'

# Is the host clock sane?
date -u; timedatectl status | grep -E 'synchronized|NTP'

# Will the file expire in the next 7 days?
openssl x509 -in /etc/ssl/cert.pem -noout -checkend 604800

# Renewal state
sudo certbot certificates 2>/dev/null | grep -E 'Name|Expiry'
kubectl get certificate -A

Conclusion

An x509: certificate has expired or is not yet valid error is a time-window failure, and the fix depends on which boundary tripped:

  1. The leaf expired — renew it and reload the server.
  2. An intermediate or root in the chain expired — reissue the leaf so it carries the current intermediate.
  3. Host clock skew makes a valid cert appear expired or not-yet-valid — fix NTP first.
  4. A stale system CA bundle references a rotated/expired anchor.
  5. The wrong (default/expired) cert is served for a missing or mismatched SNI.
  6. Automated renewal stopped silently and the on-disk cert was never updated.

Always check the full chain and the host clock before assuming the leaf is at fault — most “expired” surprises are an expired intermediate or a missed renewal, not the leaf itself.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.