What you are seeing
Browsers show an error code under the warning, often behind an "Advanced" or "Show details" button. That code tells you what is wrong with the certificate.
| Error code | What it means |
NET::ERR_CERT_DATE_INVALID (Chrome), SEC_ERROR_EXPIRED_CERTIFICATE (Firefox) | The certificate has expired, or the visitor’s clock is wrong. |
NET::ERR_CERT_COMMON_NAME_INVALID, SSL_ERROR_BAD_CERT_DOMAIN | The certificate does not list this exact hostname (www versus no www is the classic case). |
NET::ERR_CERT_AUTHORITY_INVALID, SEC_ERROR_UNKNOWN_ISSUER | Self-signed certificate, missing intermediate certificate, or traffic intercepted by antivirus or a proxy. |
ERR_SSL_PROTOCOL_ERROR | The server is not speaking TLS correctly on port 443. |
ERR_SSL_VERSION_OR_CIPHER_MISMATCH | No certificate configured for this name, or only outdated TLS versions on offer. |
You cannot visit example.com right now because the website uses HSTS | Any certificate error on an HSTS site, with no option to click through. |
| "Not secure" in the address bar, but no error page | Mixed content, or a page served over plain HTTP. |
| Cloudflare 525 or 526 | The connection between Cloudflare and your server failed the handshake (525) or the server certificate is invalid (526). |
Two industry changes matter here. Let’s Encrypt certificates last 90 days, and Let’s Encrypt stopped sending expiry reminder emails in 2025, so a broken auto-renewal now fails silently. Under a CA/Browser Forum rule, the maximum lifetime of any public certificate fell to 200 days in March 2026 and drops to 100 days in March 2027, so manual renewal is becoming unworkable everywhere.
Confirm it in two minutes
Run these on your own computer’s terminal (macOS and Linux include openssl and dig). Replace example.com with the exact hostname that shows the error.
1. Read the certificate the server actually sends.
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
-servername asks for the certificate for that name, as browsers do. Good: notAfter is in the future and the Subject Alternative Name line lists every name you use, such as DNS:example.com, DNS:www.example.com. Bad: a past date, a missing name, or a subject showing the host’s server name instead of yours (the server has no certificate set up for your site).
2. Check the chain.
echo | openssl s_client -connect example.com:443 -servername example.com 2>&1 | grep 'Verify return code'
Good: Verify return code: 0 (ok). Code 10 means expired; 18 means self-signed; 21 (unable to verify the first certificate) means the server is not sending the intermediate certificate.
3. Check every DNS record Let’s Encrypt will use.
dig +short A example.com
dig +short AAAA example.com
dig +short CAA example.com
Good: the A record is your current server’s IP, the AAAA is either empty or your current server’s IPv6 address, and CAA is empty or includes issue "letsencrypt.org" (or the authority your host uses). Bad: an old IPv6 address. Let’s Encrypt validates over IPv6 when an AAAA record exists, so a stale one breaks renewal even when IPv4 is right.
4. Check the validation path is reachable.
curl -sI http://example.com/.well-known/acme-challenge/TEST_FILE
TEST_FILE can be any made-up name. Good: a 404 from your own server, or a redirect to the HTTPS version of the same path. Bad: a 403, a redirect to another domain, or a maintenance page. Any of those block the HTTP-01 challenge.
5. Find mixed content. In the browser, press F12, open the Console tab and reload. Mixed content shows as Mixed Content: The page at 'https://example.com/' was loaded over HTTPS, but requested an insecure image 'http://...', naming each file.
Most likely causes, in order
- Auto-renewal failed. Tell: check 1 shows an expiry date in the past, and the panel’s renewal log shows
Invalid response from http://example.com/.well-known/acme-challenge/... or Timeout during connect (likely firewall problem). Fix: correct the DNS, firewall, redirect or maintenance page that blocked validation, then reissue.
- The certificate does not cover the name. Tell:
COMMON_NAME_INVALID, and the name is missing from the SAN list. Fix: reissue including every hostname, both with and without www.
- Missing intermediate certificate. Tell: fine in desktop Chrome, which can fetch missing intermediates itself, but failing on Android, in curl and in apps, with return code 21. Fix: install the full chain file from your certificate provider, not only the certificate.
- Mixed content. Tell: no error page, just a missing padlock, and console warnings naming
http:// files. Fix: change the stored URLs to https and update hard-coded links in theme files.
- CDN SSL mode does not match the origin. Tell: Cloudflare 525 or 526, or a fine certificate at the edge but expired at the origin. Fix: install a valid certificate on the server and use Full (strict).
- Too many reissue attempts. Tell: an error mentioning
too many certificates or failed authorizations. Let’s Encrypt allows 5 duplicate certificates for the same set of names per week and 5 failed validations per hostname per hour. Fix: fix the cause, then wait out the limit.
- The visitor’s device. Tell: only one person sees it; their clock is wrong, or the issuer in their browser shows their antivirus or company proxy. Fix: correct the clock, or turn off HTTPS scanning.
What it usually is not
- "We need a paid certificate." Free domain-validated certificates use the same encryption and show the same padlock. Paying fixes none of the causes above.
- An SSL plugin. A WordPress plugin cannot fix an expired or mismatched certificate. It works above the certificate, not on it.
- Browser cache. Certificate errors come from the live handshake. If openssl shows the problem, it is on the server.
What to send your host
- Every hostname affected, written out in full.
- The browser error code and when it started, in UTC.
- The output of checks 1 and 2.
- Your A, AAAA and CAA records, and where DNS is hosted.
- Whether a CDN or proxy sits in front, and its SSL mode.
- Any renewal error from the hosting panel, copied exactly.