SSL certificate expired: how to fix it, and never see it again
A practical guide to fixing an expired SSL certificate fast — what breaks, renewal flow per common provider, and how monitoring prevents recurrence.
SSL certificate expired: what happens, how to fix it, and how to never see it again
Your certificate expired. The site looks broken. The marketing email you sent thirty minutes ago links to a domain visitors can no longer trust. This article walks through what is actually broken, the fastest path to issue a new certificate per common provider, and how to make sure the next renewal happens before the deadline rather than after it.
What users see when an SSL certificate expires
The browser refuses to load the page. Exact wording varies:
- Chrome / Edge —
NET::ERR_CERT_DATE_INVALIDand a "Your connection is not private" interstitial. - Firefox —
SEC_ERROR_EXPIRED_CERTIFICATEand "Warning: Potential Security Risk Ahead". - Safari — "This Connection Is Not Private" with a "go back" recommendation.
Users have to click through an interstitial that warns them, in plain language, that the site might be unsafe. Most won't. Search rankings will start to slip if the outage lasts more than a few hours — Google's crawler treats expired-certificate failures as an availability problem.
API clients fail differently. Most language HTTP libraries will refuse to complete the TLS handshake and return an error like certificate has expired (Node.js: CERT_HAS_EXPIRED; Python: ssl.SSLCertVerificationError; Go: x509: certificate has expired or is not yet valid). Webhooks stop firing. Cron jobs that hit the affected domain crash.
Email sending also breaks if your MTA does opportunistic STARTTLS to the affected domain. Many mail servers fall back to plaintext, but increasingly receivers are configured to reject mail from domains that fail strict TLS — DANE, MTA-STS, and the new bulk-sender requirements from Gmail and Yahoo all care about whether your TLS is valid.
Step 1 — Confirm the certificate is actually expired
Before you start the renewal flow, check from a different machine. Browser caches sometimes serve a cached "expired" warning that isn't the live state. From a terminal:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -datesOutput looks like:
notBefore=Feb 14 00:00:00 2026 GMT
notAfter=May 4 23:59:59 2026 GMTIf notAfter is in the past, the certificate is genuinely expired. If it's in the future, your problem is somewhere else — caching, intermediate-cert issues, or a misconfigured server picking the wrong certificate from disk.
Step 2 — Issue a new certificate
Pick the path that matches your situation.
Let's Encrypt (most common)
If you're using certbot, the renewal command is:
sudo certbot renew --force-renewalThen reload your web server:
sudo systemctl reload nginx
# or
sudo systemctl reload apache2If certbot renew fails, check the timer that's supposed to renew automatically:
systemctl list-timers | grep certbot
sudo journalctl -u certbot.timer -n 50The most common failure modes are:
- Validation failed — the HTTP-01 challenge couldn't reach the server (firewall, redirect to HTTPS that no longer works because the cert is expired). Use the
--http-01-portflag to specify the port behind the proxy, or switch to DNS-01 for wildcard certs. - Certificate not found — the certbot config drifted. Inspect
/etc/letsencrypt/renewal/<domain>.conf.
Cloudflare-managed (Universal SSL or Advanced Certificate Manager)
Cloudflare's edge certificates renew automatically. If yours expired, the most likely cause is that your domain stopped pointing at Cloudflare nameservers, or your Cloudflare account is suspended. Confirm in the dashboard under SSL/TLS → Edge Certificates.
If you're on Advanced Certificate Manager, there's a manual reissue button. Use it; new edge certs propagate in seconds.
AWS Certificate Manager (ACM)
ACM auto-renews if and only if DNS validation records are still in place. If yours expired, run:
aws acm list-certificates --query 'CertificateSummaryList[?Status==`EXPIRED`]'Request a new certificate, copy the validation DNS records, add them to your DNS zone, then attach the new ARN to your CloudFront distribution / ELB / API Gateway. The old ARN must remain attached until the new one is in place — there's no zero-downtime hot swap, only sequential.
Manual / commercial CA (Sectigo, DigiCert, GoDaddy)
You buy a renewal, download the new certificate bundle (server cert + intermediates), upload it via your provider or paste it into your web-server config, then reload. The full chain matters — a cert that works in Chrome and breaks in Java's certificate store usually means an intermediate is missing.
Self-signed (development environments)
openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
-keyout key.pem -out cert.pem -subj "/CN=localhost"Don't use self-signed in production. Browsers and clients will warn forever, and Strict Transport Security (HSTS) will refuse to load the page entirely if the domain has previously sent an HSTS header.
Step 3 — Verify the fix worked
Don't rely on a refresh in the browser. Hit the SSL with a fresh client:
curl -vI https://example.com 2>&1 | grep -E "(SSL|expire|HTTP)"Or pull the dates with openssl again. Check from a vantage point you know is uncached — a different ISP, mobile data, or a cloud VM. If the new certificate is in place but the old is still being served from somewhere, you have a CDN cache, a load-balancer pinning to one origin, or a forgotten subdomain on a different server.
Also check the chain:
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | grep "subject\|issuer"A complete chain shows your server cert, then one or two intermediates, then the trusted root. Java and some mobile platforms will reject a chain that's missing an intermediate even when desktop browsers accept it.
Step 4 — Restore email-sending TLS if you use opportunistic STARTTLS
If the expired certificate was on your MTA (port 25), receivers may have queued mail for retry. Most senders will retry for 24–48 hours. Once the new certificate is in place, the queue will drain on its own. Confirm by sending a test message to a Gmail address and checking the message headers for TLS=TLS1.3 (or whatever version your MTA supports) on the receiving hop.
Why this happened — and how to make it stop
Expired certificates are almost always a renewal-process failure, not a TLS-config failure. The four common causes:
- Auto-renewal got broken three months ago, nobody noticed. Certbot's renewal timer crashed, or the IAM role it uses for DNS-01 lost permissions. Renewal failures don't surface until the cert is one minute past expiry.
- The contact email on the certificate was a person who left the company. Let's Encrypt sends warning emails 20, 10, and 1 day before expiry. They went to a black hole.
- Manual renewal — someone forgot. Annual renewals are a calendar reminder away from being completely fine. The reminder gets dismissed during a busy week.
- A migration broke the renewal path. Moved DNS to a new provider, the validation records didn't move with it. Moved to a new server, certbot stayed behind.
The fix for all four is the same: monitor the certificate expiry yourself, separately from the renewal pipeline.
Set up SSL expiry monitoring (the part that prevents recurrence)
DomainCare watches every certificate on every domain you add. The SSL check fires four times a day (every 6 hours by default — configurable on Pro and Business plans), parses the certificate, tracks the notAfter date, and sends you an alert at 30 / 14 / 7 / 3 / 1 days before expiry. If your renewal pipeline silently breaks, the monitoring catches it long before users do.
You can also self-host this with a simple cron — a one-liner with openssl and a Slack webhook will do it for one domain. Past five domains the maintenance overhead exceeds the cost of a paid monitor. Past twenty it's a guaranteed source of pages at 3 AM.
The threshold that matters most is 30 days. That's enough time to debug a broken auto-renewal, get help from a colleague, or escalate to your CA without an outage.
Related
- SSL certificate types compared — DV vs OV vs EV, wildcards, multi-domain.
- SSL check reference — what DomainCare's SSL check verifies on every run.
ssl_cert_expiredalert — what fires, when, and how to silence it during planned migrations.
Common questions
My cert is technically valid but Chrome still says it's expired. Browser cache. Hard-refresh with Cmd+Shift+R / Ctrl+Shift+R. If still broken, check from incognito or another browser.
Can I renew before the cert expires without an outage? Yes — that's the whole point of monitoring. You renew at 14 days out, deploy the new certificate, and the old one's expiry passes silently because nothing was using it anymore.
Does Let's Encrypt auto-renewal really need internet access on port 80? Not necessarily — DNS-01 challenges work over your DNS provider's API, no port-80 access required. Use this if your origin only listens on 443 or sits behind a CDN.
My cert is from a CA that doesn't exist anymore (StartCom, WoSign, Symantec). You need a new one from a currently-trusted CA. Browsers stopped trusting these years ago; if you're still serving them, modern clients have been failing for a while.