Common SSL Certificate Errors and How to Fix Each One

Fix expired certificates, name mismatches, incomplete chains and mixed content warnings with clear diagnosis steps and openssl, Nginx and Apache commands.

By the MakeItFlow team Updated 8 min read
Share LinkedIn X Facebook WhatsApp
Common SSL Certificate Errors and How to Fix Each One

A certificate error is one of the few website problems that stops visitors cold. The browser shows a full-page warning, most people leave, and anything that talks to your site over an API starts failing. The good news is that almost every TLS problem falls into one of four groups: expired, wrong name, broken chain, or mixed content. Each one has a clear way to diagnose it. This guide shows you how to tell which one you have and how to fix it.

Key takeaways

  • Almost every certificate error is an expired certificate, a name mismatch, an incomplete chain or mixed content, and each has a clear diagnosis.
  • An expired certificate usually means automated renewal broke quietly, or the web server was never reloaded after a successful renewal.
  • If a site works in Chrome but fails in curl or apps, serve the full chain file such as fullchain.pem rather than the leaf certificate alone.
  • Fix mixed content at the source by updating old http:// links, and use upgrade-insecure-requests only as a backstop.

First, identify the error

Browsers name the problem in the warning page, usually under "Advanced". Map what you see to the sections below:

What the browser shows Likely cause Section
NET::ERR_CERT_DATE_INVALID (Chrome/Edge), SEC_ERROR_EXPIRED_CERTIFICATE (Firefox) Expired or not-yet-valid certificate Expired certificate
NET::ERR_CERT_COMMON_NAME_INVALID, SSL_ERROR_BAD_CERT_DOMAIN Hostname not on the certificate Name mismatch
NET::ERR_CERT_AUTHORITY_INVALID, SEC_ERROR_UNKNOWN_ISSUER Missing intermediate, self-signed, or untrusted CA Incomplete chain
Padlock missing or "Not secure" on an HTTPS page, console warnings HTTP resources on an HTTPS page Mixed content
ERR_SSL_VERSION_OR_CIPHER_MISMATCH No certificate for that hostname, or outdated TLS settings Name mismatch / server config

If you have the certificate or chain file itself, paste it into our SSL Certificate Decoder to check the SANs, expiry and chain order before you install it. The fastest way to see what your server actually presents is openssl:

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null

And to read the key fields of the leaf certificate:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

Always pass -servername. Without it, a server hosting several sites may hand you the wrong certificate, and you'll chase a problem that doesn't exist.

1. Expired certificate

Symptoms: Every visitor gets the warning at once, usually on a weekend, exactly 90 days (or whatever the lifetime is) after the last renewal.

Why it happens: Automated renewal broke quietly. Common causes are a cron job or systemd timer that stopped running, an HTTP-01 challenge now blocked by a redirect, firewall or CDN rule, a DNS API token that expired, or a renewal that succeeded but the web server was never reloaded, so it is still serving the old file from memory.

Fix:

# See what Certbot manages and when each certificate expires
sudo certbot certificates

# Test renewal without changing anything
sudo certbot renew --dry-run

# Renew, then reload the web server so it picks up the new files
sudo certbot renew
sudo systemctl reload nginx   # or: sudo systemctl reload apache2

If --dry-run fails, the error message tells you which challenge failed and why. Fix that, not the symptom. Then compare the notAfter date from openssl x509 -dates with the file on disk. If the disk is newer, you forgot the reload. Certbot can do this for you with a deploy hook: --deploy-hook "systemctl reload nginx".

Also check: If only one visitor sees "expired" on a valid certificate, their device clock is wrong. That's a client-side problem.

Don't rely on reminder emails. Let's Encrypt stopped sending expiration notification emails in June 2025, and certificate lifetimes are getting shorter across the industry (see the certificate lifetime schedule). Monitor expiry from outside your server instead.

2. Name mismatch

Symptoms: The certificate is valid, but not for the hostname in the address bar.

Why it happens:

  • The certificate covers example.com but not www.example.com, or the reverse.
  • A wildcard *.example.com covers shop.example.com but not example.com itself, and not a.b.example.com. Wildcards match exactly one label.
  • The server has no virtual host for that name and falls back to its default certificate, often your hosting provider's own.
  • DNS points the hostname at the wrong server, for example an old host after a migration.

Browsers only look at the Subject Alternative Name (SAN) list. The Common Name field is ignored. Check the SANs with the -ext subjectAltName command above.

Fix: Issue a certificate that includes every hostname you serve:

sudo certbot --nginx -d example.com -d www.example.com

Then make sure the right server_name (Nginx) or ServerName/ServerAlias (Apache) block is the one serving that hostname. If you redirect www to the apex, the www host still needs a valid certificate, because the redirect happens after the TLS handshake.

If issuance itself fails, check your CAA records. A CAA record that only authorizes one CA blocks every other CA from issuing. Our CAA records guide explains how to read them.

3. Incomplete certificate chain

Symptoms: The site works in your desktop browser but fails in curl, in some mobile apps, in payment-provider webhooks, or on some Android devices. SSL checkers report "chain incomplete" or "extra download required".

Why it happens: Your certificate is signed by an intermediate CA, and the intermediate is signed by a root that devices trust. The server must send your certificate and the intermediate(s). If it only sends the leaf, clients have to find the intermediate themselves. Some desktop browsers fetch or cache intermediates automatically, which hides the problem from you while other clients fail.

Fix: Serve the full chain file, not just the certificate.

With Certbot, that means fullchain.pem, not cert.pem:

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

On Apache 2.4.8 and later, SSLCertificateFile can point to the full chain as well:

SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

If you bought a certificate from a commercial CA, they'll provide a "CA bundle". Concatenate your certificate first, then the intermediates, and don't include the root:

cat example_com.crt intermediate_bundle.crt > example_com_fullchain.crt

Verify the result. openssl s_client -showcerts should list at least two certificates, and the output should end with Verify return code: 0 (ok).

Self-signed or private CA: If the issuer is your own CA, a hosting control panel's default certificate, or a firewall that intercepts TLS, public clients will never trust it. Replace it with a certificate from a public CA. Let's Encrypt is free.

A related warning: If Nginx logs warnings about OCSP stapling after a Let's Encrypt renewal, that's because Let's Encrypt shut down its OCSP service in 2025 and its certificates no longer include an OCSP URL. Remove ssl_stapling and ssl_stapling_verify for those certificates.

4. Mixed content

Symptoms: The page loads over HTTPS, but the padlock is missing or the browser says "Not secure". Parts of the page may be broken: missing styles, dead sliders, forms that don't submit.

Why it happens: The HTML references http:// resources. Per MDN, current browsers handle them in two groups:

  • Upgradable (images, audio, video via src): automatically requested over HTTPS. If the HTTPS version doesn't exist, it fails to load.
  • Blockable (scripts, stylesheets, iframes, fonts, fetch/XHR, images using srcset or <picture>): blocked outright.

Requests to raw IP addresses are never upgraded, so http://203.0.113.10/logo.png is simply blocked.

Fix:

  1. Open DevTools (F12) > Console and reload. Each mixed content warning names the offending URL.
  2. Fix it at the source. On WordPress, the usual culprit is old absolute URLs in the database after moving to HTTPS. A search-replace with WP-CLI handles it:
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid --dry-run
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid
  1. Update hard-coded http:// links in themes, templates and third-party embed codes.
  2. As a safety net, add the CSP directive below. It upgrades all remaining subresource requests, including blockable ones:
Content-Security-Policy: upgrade-insecure-requests

Treat it as a backstop, not the fix. Any resource whose host has no HTTPS will still fail.

Prevent the next one

  • Automate renewal and reloads. Use a deploy hook so the server reloads after renewal.
  • Monitor from outside. Check the certificate your server actually serves, on every hostname, rather than the file on disk.
  • Keep an inventory. Know which hostnames exist and which certificate covers each one. Certificate transparency logs (crt.sh) show everything issued for your domain.
  • Test after changes. Run the openssl commands above after migrations, CDN changes and server rebuilds.

Frequently asked questions

Why does my site work in Chrome but fail in curl or an app?

Almost always an incomplete chain. Chrome can fill in a missing intermediate itself, while curl and many app libraries can't. Serve fullchain.pem (or your CA's bundle) and test again with openssl s_client.

Can I tell visitors to click "Proceed anyway"?

No. It trains users to ignore real attacks, and if your site uses HSTS, browsers won't even offer the option. Fix the certificate.

Does Cloudflare fix certificate errors for me?

Cloudflare provides the certificate visitors see at the edge, which solves most expiry and mismatch problems for proxied hostnames. In Full (strict) mode, though, your origin still needs a valid certificate. Hostnames set to DNS-only bypass Cloudflare and use whatever your server presents.

How early should a certificate renew?

Let's Encrypt recommends using ACME Renewal Information (ARI) where your client supports it, and otherwise renewing when about two-thirds of the lifetime has passed. For a 90-day certificate, that's about 30 days before expiry.

What to do next

Run the openssl commands against every hostname you own, not just the homepage, and make sure each one returns Verify return code: 0 (ok) with an expiry date comfortably in the future. To check certificate validity, hostname coverage and HTTPS headers in one pass, run a free audit. Then read our HSTS guide to make sure visitors never hit the HTTP version at all.

Sources

#ssl certificate #tls #https #mixed content #certificate chain

Written by the MakeItFlow team

We build the website audit these guides are based on. Every fact is checked against the primary sources listed above and this guide was last reviewed on 31 October 2026 . How we research and check

Share LinkedIn X Facebook WhatsApp

Check your own site in 30 seconds

Run a free audit covering speed, SEO, DNS, email authentication and security headers — and get a prioritised fix list.

Weekly newsletter

One practical website fix, every week

New guides on speed, SEO, email deliverability and security — straight to your inbox. No spam, unsubscribe in one click.

Keep reading