ERR_CERT_DATE_INVALID: Causes and the Fix

· 4 min read · 6 views · Getwebup

The short answer

ERR_CERT_DATE_INVALID means the certificate is outside its validity window - it has expired, has not started yet, or your device's clock is wrong. Check your own clock first, since a wrong date makes every HTTPS site fail at once. If the clock is right, run openssl s_client -connect yourdomain.com:443 | openssl x509 -noout -dates to see the real expiry.

Not sure which error you have? Decode Chrome's code first — "This Site Can't Be Reached" in Chrome: Every Code Decoded

ERR_CERT_DATE_INVALID has two completely different causes and one of them has nothing to do with the website. The certificate is outside its validity window - either because it genuinely expired, or because your device thinks it is a different date than it is. Deciding which takes about five seconds.

Check your own clock first

Open any other HTTPS site - a search engine, a news site, anything. If they all fail the same way, the certificates are fine and your device's date is wrong. This happens after a dead CMOS battery, on a machine restored from an old image, and on phones that have lost network time.

timedatectl                       # Linux
sudo sntp -sS time.apple.com      # macOS, force a sync
w32tm /resync                     # Windows, elevated prompt

Set the clock, enable automatic synchronisation, reload. If every site now works, you are done and no certificate was ever at fault.

If only one site fails, read the actual dates

openssl s_client -connect yourdomain.com:443 -servername yourdomain.com </dev/null 2>/dev/null \
  | openssl x509 -noout -dates -subject

You get two lines, notBefore and notAfter. A notAfter in the past is a plain expiry. A notBefore in the future is rarer and means a certificate was installed ahead of its start date, which some CAs backdate by a few hours to allow for clock skew.

The renewal that ran and did not help

This is worth checking before you go looking for a failed renewal, because it looks identical from a browser. Web servers load the certificate at startup and keep it in memory. Certbot writes new files and, unless a deploy hook tells the server, nothing on the wire changes.

openssl x509 -in /etc/letsencrypt/live/yourdomain.com/fullchain.pem -noout -dates
systemctl reload nginx

If the file on disk is current and the served certificate is not, the reload is the entire fix. Make it automatic so it does not recur:

certbot renew --deploy-hook "systemctl reload nginx"

When the renewal genuinely failed

Do not wait for the next scheduled attempt to find out why. Ask now:

certbot renew --dry-run
systemctl list-timers | grep certbot

The dry run reproduces the real failure without touching rate limits. Three causes account for most of them.

  • The HTTP-01 challenge cannot reach the server. Let's Encrypt fetches a file under /.well-known/acme-challenge/ over plain HTTP. A blanket HTTP-to-HTTPS redirect is fine - the redirect is followed - but a WAF rule, a firewall, or a deny all on hidden directories is not. Test it by hand: put a file there and fetch it from outside.
  • DNS moved. If the domain now points somewhere else, the challenge is served by a different machine and validation fails on the one holding the certificate.
  • The timer is off. A migration or a restore can leave certbot.timer disabled, and nothing complains until an expiry three months later. systemctl enable --now certbot.timer puts it back.

On cPanel and shared hosting

AutoSSL renews certificates on a schedule and reports failures in WHM under SSL/TLS → Manage AutoSSL → Logs. The usual reasons it stops are a domain that no longer resolves to the server, a subdomain added after the last successful run, and a redirect that breaks the validation request. The log names the failing domain explicitly, which saves guessing.

Catch the next one before it happens

The reason expiry is such a common outage is that the warning email and the renewal both depend on things that quietly stop working. Independent monitoring costs nothing:

echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null \
  | openssl x509 -noout -checkend $((14*86400)) \
  || echo "certificate for yourdomain.com expires within 14 days"

Run that from cron on a different machine than the one holding the certificate. Checking from the same server is how a failed renewal and a failed alert end up sharing a cause.

Questions people actually ask