SSL certificate errors: what they mean and how to fix them
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:
- The chain of trust. The certificate must be signed by a certificate authority (CA) the system or browser trusts, usually through an intermediate certificate.
- The name. The domain in the address bar must be listed in the certificate (in the SAN field).
- The dates. The certificate must be valid today, both already and still.
- 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.comandwww.example.comare two different names and both must be in the certificate,- a wildcard
*.example.comcoverswww.example.comandshop.example.com, but notexample.comitself ora.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.