routing.pl

SSL certificate errors: what they mean and how to fix them

08.06.20266 min readDomains and certificates

An expired certificate, a missing intermediate, a name mismatch and old TLS, the most common browser warnings and their causes on the server side.

“Your connection is not private” is a message that reliably scares visitors away. The browser shows it when it cannot confirm that it is talking to the right server. The good news: there are only a few causes, and they can almost always be fixed on the server side in a few minutes.

What the browser checks

On every HTTPS connection the browser verifies four things:

  1. The chain of trust. The certificate must be signed by a certificate authority (CA) the system or browser trusts, usually through an intermediate certificate.
  2. The name. The domain in the address bar must be listed in the certificate (in the SAN field).
  3. The dates. The certificate must be valid today, both already and still.
  4. The protocol. The server must support a TLS version and ciphers the browser accepts.

Each of the errors below is a failure of one of these conditions.

The most common errors

Message (Chrome) Cause Fix
NET::ERR_CERT_DATE_INVALID the certificate has expired (or the visitor’s clock is wrong) renew the certificate and set up automatic renewal
NET::ERR_CERT_COMMON_NAME_INVALID the name in the address bar is not in the certificate, e.g. example.com is there but www.example.com is missing issue a certificate covering every name you use
NET::ERR_CERT_AUTHORITY_INVALID a self-signed certificate, or the server does not send the intermediate certificate use a certificate from a trusted CA and configure the full chain
ERR_SSL_VERSION_OR_CIPHER_MISMATCH the server supports only old TLS versions or ciphers enable TLS 1.2 and TLS 1.3
padlock with a warning, “connection is not fully secure” mixed content: an HTTPS page loads images or scripts over HTTP change resource URLs to https:// or relative ones

The missing intermediate certificate

This is the sneakiest error, because “it works for me”. Desktop Chrome and Firefox can fetch a missing intermediate on their own or already have it cached, so the site opens normally. Android, curl, mobile apps, API integrations and some mail clients, however, report a trust error.

The fix: the server must send the domain certificate together with the intermediate. With Let’s Encrypt and certbot this means fullchain.pem, not cert.pem:

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

In Apache (2.4.8 and later) point SSLCertificateFile at the same fullchain.pem. For certificates bought elsewhere, append the intermediate (the bundle) after the domain certificate in a single file.

Names in the certificate and wildcards

A certificate covers exactly the names listed in it. A few things that often surprise people:

  • example.com and www.example.com are two different names and both must be in the certificate,
  • a wildcard *.example.com covers www.example.com and shop.example.com, but not example.com itself or a.b.example.com,
  • certificates for IP addresses are rare. Visitors reach a website by its domain name.

Expiry and automatic renewal

Let’s Encrypt certificates are valid for 90 days, and certbot tries to renew them about 30 days before they expire. If renewal fails, nobody will remind you any more, because Let’s Encrypt stopped sending expiry e-mails in 2025. So it is worth checking that renewal really works:

systemctl list-timers | grep certbot   # is the job scheduled
certbot renew --dry-run                # test renewal

A common trap: the certificate renews correctly, but the web server keeps serving the old one because nobody reloaded it. Add a hook to certbot, e.g. --deploy-hook "systemctl reload nginx".

Automation is no longer optional for paid certificates either. Under a CA/Browser Forum decision, from March 2026 a certificate can be valid for at most 200 days, from 2027 for 100 days, and from 2029 for only 47 days. Renewing by hand once a year is becoming a thing of the past.

When DNS is to blame

Sometimes the certificate is fine and the domain simply leads to the wrong place. Check in DNS lookup:

  • an AAAA record pointing to an old server. Visitors on IPv6 then reach a different machine with an old certificate, while you see everything correctly over IPv4,
  • a CAA record that allows only selected authorities to issue certificates. If you switch certificate provider, add it to CAA, otherwise issuance will fail,
  • a recent record change that has not propagated yet. Some visitors see the old server until the TTL expires.

How to check

The SSL/TLS checker connects to the server the way a browser does and shows the certificate, the whole chain, the expiry date and the supported protocol versions. From the command line you can do the same with:

openssl s_client -connect example.com:443 -servername example.com

The -servername option matters: many websites often share one IP address, and without it the server may return the certificate of a completely different domain.

Do not ask visitors to "click Advanced and proceed". It teaches them to ignore warnings, and with HSTS enabled the browser will not allow it anyway. Fix the certificate.