lintpageincident.log
checksenvironmentstoolsblogfaq
sign inget started
~/blog/ssl-certificate-expiry
SecuritySSLHTTPSTutorial

An Expired SSL Certificate Takes Your Whole Site Down at Once

Marius Orzaru·June 20, 2026·8 min read

An expired SSL certificate is not a soft failure. It takes the whole site down at once.

Most write-ups on SSL treat an expired certificate like a warning you can dismiss, something that nags a few cautious visitors while everyone else carries on. That is not how browsers handle it. When the certificate date is invalid, Chrome, Safari, and Firefox stop rendering your site entirely and replace it with a full-screen interstitial: NET::ERR_CERT_DATE_INVALID, "Your connection is not private." Almost nobody clicks through that. The page your visitor wanted is simply gone, and so is every form, login, and API call behind it.

The cruel part is that the failure is binary and global. There is no slow degradation, no canary, no partial rollout. One minute the padlock is green for everyone, the next minute every new visitor hits a wall. And the reason it sneaks up on teams is that the thing meant to prevent it, auto-renewal, fails silently for boring, undramatic reasons. This post covers what actually breaks, why "it works in my browser" is not proof, and the four certificate properties worth checking on a schedule.

What's in this post

  • Why an expired cert is total, not partial
  • Why "it works in my browser" is a lie
  • Auto-renewal fails silently, and why
  • The trust chain: self-signed and missing intermediates
  • Protocol version and the apex-vs-www gotcha
  • Checking all of it in one scan

Why an expired cert is total, not partial

A 404 takes down one URL. A bad deploy might take down one route. An expired TLS certificate takes down the origin. The browser validates the certificate during the TLS handshake, before it has fetched a single byte of HTML, so the failure happens upstream of everything your application does. It does not matter that your server is healthy, your database is up, and your HTML is perfect. The handshake fails, and the browser refuses to proceed.

That is also why it is not just "the homepage looks broken." Anything that speaks HTTPS to your origin breaks at the same instant:

WHAT BREAKS WHEN THE CERT EXPIRES
---------------------------------------------------------------
Page loads      | full-screen interstitial, no content rendered
Form submits    | POST never reaches the server
Fetch / XHR     | requests reject with a network error
Third-party API | webhooks and server-to-server calls fail TLS
Mobile apps     | anything pinned to your HTTPS endpoint dies
Crawlers        | Googlebot cannot complete the handshake

The interstitial is intentionally hard to bypass. Browsers want it to be hard, because the whole point of TLS is that an invalid certificate could mean an active attacker. From the browser's perspective an expired cert and a hostile one are indistinguishable, so it errs on the side of stopping the user cold. The web.dev explainer on why HTTPS matters is blunt about this: there is no minor breakage, and there is no safe way for users to opt out at scale.

Why "it works in my browser" is a lie

Here is the trap that lets a broken certificate sit live for hours. You get the alert, you open the site, the padlock is green, and you close the ticket. The site is still down for everyone else.

Two layers of caching are lying to you. First, browsers and the OS keep validated certificates and TLS session state around. Once your browser has completed a successful handshake with your origin, it can resume that session without doing a full re-validation, so you keep loading the site happily while a visitor with a cold connection gets rejected at the handshake. Second, you almost certainly have an HSTS and connection state warmed up that a first-time visitor does not.

The fix is to test the way a stranger's browser does: a fresh connection, no cached session, validating the chain from scratch. Do not eyeball the padlock. Read the live certificate over the wire.

# Read the live cert and print its validity window.
# This does a fresh handshake, like a brand-new visitor.
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates -subject -issuer

# notBefore=...
# notAfter=Sep  3 12:00:00 2026 GMT   <- this is the line that matters

The notAfter date is the one that takes you down. If you want a single number to alert on, compute days remaining and treat anything less than or equal to 14 days as urgent and anything already past as a live outage, not a warning:

# Days until expiry for a host. Negative means already expired.
expiry=$(echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -enddate | cut -d= -f2)
echo $(( ( $(date -jf "%b %e %T %Y %Z" "$expiry" +%s) - $(date +%s) ) / 86400 )) days left

The point is not the exact one-liner, which varies by platform (the date -jf syntax above is BSD/macOS; GNU/Linux uses date -d). The point is that the check has to originate from outside your warmed-up browser session, because your browser is the one client on earth most likely to tell you everything is fine.

Auto-renewal fails silently, and why

Most certificates today are short-lived and renewed by a robot, which is good, until the robot stops. Let's Encrypt issues certificates that are valid for 90 days and the standard advice is to renew with about 30 days of life left, so a healthy setup replaces the cert roughly every 60 days with a 30-day safety buffer. That buffer is the only thing standing between a single failed renewal and an outage, and it expires quietly.

Renewal fails for unglamorous reasons, and none of them throw an error your monitoring would see:

WHY AUTO-RENEWAL QUIETLY STOPS
---------------------------------------------------------------
DNS changed      | the ACME challenge can no longer be validated
Cron stopped     | the renewal timer was removed or never enabled
Rate limited     | too many issuance attempts hit the CA's cap
Port 80 blocked  | the HTTP-01 challenge can't reach the server
Billing lapsed   | a paid CA's card expired, issuance suspended
Reload skipped   | cert renewed on disk but the server never reloaded

That last one is a classic: certbot renews the file, but nothing reloads nginx, so the process keeps serving the old certificate from memory until it expires. The renewal "succeeded" and the site still goes down. The failure mode is always the same shape: something that used to run every couple of months stopped running, and nobody noticed because nothing was on fire. The only reliable defense is an external check on the actual served certificate, on a schedule, that does not trust the renewal job's own logs.

The trust chain: self-signed and missing intermediates

Expiry is the most common way a certificate breaks, but "not trusted" is the second, and it produces the same full-screen interstitial. A certificate is trusted only when it chains up to a certificate authority that browsers ship in their root store. Two failures account for most "not trusted" verdicts.

The first is a self-signed certificate, where you signed it yourself instead of a recognized CA. It is perfectly valid cryptographically and completely untrusted by every browser, because nothing vouches for it. This is common when a staging cert leaks into production or someone generates a quick cert to "make HTTPS work."

The second is sneakier and far more common in production: a missing intermediate certificate. Your server is supposed to send the leaf certificate plus the intermediate(s) that link it to the trusted root. If you install only the leaf, the chain is broken. The certificate is real, issued by a real CA, and not expired, but the browser cannot build a path from your certificate to a root it trusts, so it rejects it. The trap here is that this often "works in my browser," because some clients cache intermediates from past visits while a fresh client does not, the exact same illusion as before.

# Verify the chain the server actually sends. A clean chain ends in:
#   Verify return code: 0 (ok)
# A missing intermediate shows:
#   verify error:num=20:unable to get local issuer certificate
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
  | grep -E "Verify return code|verify error"

If you see unable to get local issuer certificate, you are missing an intermediate. Fix it by serving the full chain (the fullchain file your CA gives you), not just the leaf.

Protocol version and the apex-vs-www gotcha

Two more properties decide whether real clients can connect. The first is the TLS protocol version. TLS 1.0 and 1.1 are long deprecated and increasingly refused outright; modern clients expect TLS 1.2 at minimum, with TLS 1.3 preferred. A server stuck on an old protocol will see handshakes fail from up-to-date browsers even when the certificate itself is fine.

The second is the one that bites launches: Subject Alternative Names, the list of hostnames a certificate actually covers. A certificate issued for example.com does not automatically cover www.example.com. They are different names, and the SAN list has to include both. The failure is asymmetric and easy to miss: you test the apex, it loads, you ship, and every visitor who types or links the www host hits a name-mismatch interstitial.

# List the names the certificate actually covers.
# If you serve www but only example.com is listed, www is broken.
echo | openssl s_client -servername www.example.com -connect www.example.com:443 2>/dev/null \
  | openssl x509 -noout -ext subjectAltName

# X509v3 Subject Alternative Name:
#     DNS:example.com, DNS:www.example.com

The rule is simple: every hostname you actually serve over HTTPS, including the redirect source, needs to be in the SAN list of the certificate that host presents. A redirect from www to apex still requires www to complete its own handshake first, so the www host needs a valid, covering certificate even if it only ever redirects. While you are checking certificates, it is worth confirming your security headers too, because HSTS in particular interacts directly with how strictly browsers enforce all of this.

Checking all of it in one scan

Every check above can be done by hand with openssl, and you should know how, but doing it on a schedule, from outside your own warmed-up browser, across both your apex and www hosts, is exactly the kind of boring recurring task that quietly stops happening, the same way the renewal cron did. That is how certificates expire on live sites run by people who absolutely knew better.

The SEO stakes are real but secondary. HTTPS has been a lightweight Google ranking signal since 2014, and Chrome marks plain HTTP as "Not Secure," but the bigger risk is not the missing ranking nudge. It is that a crawler hitting a broken certificate cannot complete the handshake at all, so it cannot reach your HTTPS pages, and over repeated failed crawls that costs you far more than the modest HTTPS boost was ever worth.

The LintPage SSL Certificate Checker does the fresh-connection check for you: it connects to your domain over TLS, reads the live certificate, and reports the expiry date and days remaining, the issuer and subject, whether the chain is trusted (catching self-signed certs and missing intermediates), the TLS protocol version negotiated, and the Subject Alternative Names so you can confirm both apex and www are covered. It also confirms that HTTPS is served and that HTTP redirects to it.

§ try this tool
SSL Certificate Checker
Check your SSL certificate: expiry date, issuer, and trust chain.
try it free →

A broken certificate rarely travels alone with the other things that quietly break a launch, so it is worth running the full pre-launch SEO checklist and the complete audit at the same time.

The 30-second version

An expired or untrusted TLS certificate is not a soft warning, it is a full-screen interstitial (NET::ERR_CERT_DATE_INVALID) that almost no visitor clicks past, so it takes the whole origin down at once: pages, forms, APIs, and crawlers all fail at the handshake. "It works in my browser" proves nothing, because your browser caches validated certs and resumes sessions while a fresh visitor gets rejected, so always read the live certificate over a cold connection. Auto-renewal (Let's Encrypt issues ~90-day certs and renews around the 30-day mark) fails silently for dull reasons: DNS changes, a dead cron, rate limits, a lapsed card, or a server that renewed the file but never reloaded. Watch four properties: days remaining (treat less than or equal to 14 as urgent), a trust chain that is not self-signed and not missing an intermediate, a modern TLS version, and a SAN list that actually covers both your apex and your www host. Check them from outside your warmed-up browser, on a schedule, because that schedule is the exact thing that quietly stops running.

§ about the author
Marius OrzaruFounder, LintPage (BludeskSoft)

I built LintPage after a single stray noindex tag slipped into production and quietly cost us 47 days of organic traffic. It now runs the 60 automated checks I wish we had run before that deploy.

LinkedIn →
§ faq

Questions, answered.

What happens when an SSL certificate expires? +
Browsers stop rendering your site and show a full-screen NET::ERR_CERT_DATE_INVALID warning ("Your connection is not private") that almost no visitor clicks past. The failure happens during the TLS handshake, before any HTML loads, so it is total: pages, forms, fetch calls, third-party APIs, and crawlers all break at once. An expired certificate is a live outage, not a soft warning.
Why does my site work in my browser but not for visitors? +
Your browser caches validated certificates and resumes existing TLS sessions, so it can keep loading a site whose certificate a fresh visitor would be rejected from. The green padlock you see proves your warmed-up connection works, not that a cold one does. Always read the live certificate over a brand-new connection with a tool or openssl, never by eyeballing the padlock.
How often should I check my SSL certificate if it auto-renews? +
Check on a schedule even with auto-renewal, because renewal fails silently. A renewal cron can stop, DNS changes can break the challenge, rate limits or a lapsed billing card can block issuance, or the cert can renew on disk while the server never reloads it. An external check on the actually-served certificate is the only reliable safety net, since renewal logs can claim success while the site goes down.
What does "certificate not trusted" mean and how do I fix it? +
A certificate is trusted only when it chains up to a certificate authority in the browser root store. The two common causes of "not trusted" are a self-signed certificate, which no authority vouches for, and a missing intermediate certificate, where the server sends only the leaf and breaks the chain. Fix the second by serving the full chain (the fullchain file from your CA), not just the leaf certificate.
Does a certificate for example.com also cover www.example.com? +
No. A certificate covers only the hostnames in its Subject Alternative Name (SAN) list, and example.com does not automatically include www.example.com. They are separate names that both have to be listed. Even a www host that only redirects to the apex must complete its own handshake first, so it still needs a valid certificate that covers the www name, or visitors hit a mismatch warning.

Get notified when we publish new posts.

§ run all 60 checks at once

Want the full picture? Stop checking one thing at a time.

Get a complete pre-launch SEO audit of your site with a single click.

run a full audit →
lintpage

Pre-launch SEO linting for developers. Catch disasters before they ship.

Product

  • Overview
  • Pre-launch checks
  • Full audit

Free tools

  • Meta tag checker
  • Robots.txt validator
  • AI crawler checker
  • OG preview
  • Sitemap validator
  • Heading checker
  • SSL checker
  • Redirect checker
  • Structured data validator
  • Broken link checker
  • Core Web Vitals checker
  • Security headers checker
  • Canonical tag checker
  • All tools →

Resources

  • Blog
  • About
  • RSS feed
  • Contact

Legal

  • Privacy
  • Terms
© 2026 lintpage. All rights reserved.built after one too many post-mortems.