SSL certificate valid but the browser shows an error: five causes and how to check each one
Updated Oct 2026 · 11 min readWhen the expiry date is fine and visitors still get a warning, the problem is almost always in what the server sends, not in the certificate you bought.
openssl s_client -servername, then repeat the test for each IP address behind the name."The certificate is valid until next year" is often true, and often beside the point. The certificate file on the server can be perfect while visitors receive something else: a chain with a missing piece, a default certificate, or the certificate of a server you forgot about. This guide goes through five common causes, with the command that confirms each one.
What the browser actually checks
When a visitor opens https://www.example.com, the browser receives one or more certificates from the server and checks, among other things, that:
- 1The chain leads to a trusted root. The site's certificate is signed by an intermediate authority, itself linked to a root the browser trusts. The server is expected to send the intermediates.
- 2The name matches.
www.example.commust appear in the certificate's Subject Alternative Name (SAN) list, exactly or through a wildcard. - 3The dates are valid, according to the visitor's clock.
Chrome reports these failures with distinct codes, defined in Chromium's source: NET::ERR_CERT_AUTHORITY_INVALID when it cannot build a trusted chain, NET::ERR_CERT_COMMON_NAME_INVALID when the name does not match, and NET::ERR_CERT_DATE_INVALID for dates. Only the last one is about expiry. The code on the warning page is your first clue.
Start every diagnosis with the certificate the server sends for the name, as seen from outside:
host=www.example.com
openssl s_client -connect "$host:443" -servername "$host" -showcerts </dev/null 2>/dev/null \
| grep -E '^ *[0-9]+ s:|^ *i:|Verify return code'
echo | openssl s_client -connect "$host:443" -servername "$host" 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltNameThe first command lists the certificates sent and ends with Verify return code: 0 (ok) when the chain checks out. The second prints the dates and the names covered (OpenSSL 1.1.1 or later).
1. The chain is incomplete
The server sends the site's certificate but not the intermediate certificate that links it to the root. The nginx documentation describes this exact case: the server certificate must be followed by the intermediate ones in the same file. With Certbot, the Certbot documentation says to use fullchain.pem (server certificate first, then intermediates) for nginx's ssl_certificate, not cert.pem.
Why it is confusing: it often works on your machine. nginx notes that browsers keep intermediate certificates they have already received, so a browser that visits many sites may not complain. Firefox goes further and preloads the intermediate certificates known to Mozilla, while some other software fetches the missing intermediate from the address written in the certificate. A fresh phone, an API client, a payment provider's webhook or a monitoring tool may not do any of this and fail.
How to confirm. In the output of the first command, look at what is listed and at the final line. A single certificate (0 s: only) with a verify error such as unable to verify the first certificate or unable to get local issuer certificate usually means the intermediate is missing.
Fix. Install the full chain provided by the authority, the site certificate first, then reload the server.
2. The name is not covered by the certificate
The certificate is valid, but for another name. Common cases:
- www versus the bare domain. A certificate for
example.comdoes not coverwww.example.com, and the reverse. - Wildcards cover one level. RFC 9525 says a wildcard can only be the complete left-most label and matches a single label:
*.example.comcoversshop.example.com, notexample.comand notapi.eu.example.com. - A name added later. A new subdomain pointed at a server whose certificate was issued before it existed.
- Only the Common Name. Chrome stopped accepting the Common Name as a fallback in Chrome 58 (2017); the name must be in the SAN list.
How to confirm. The subjectAltName line of the second command lists every name covered. If the name in the address bar is not there, that is the cause. Chrome shows NET::ERR_CERT_COMMON_NAME_INVALID.
Fix. Reissue the certificate with every name the site answers on, including www and the bare domain if both are used.
3. The server presents another certificate
Several sites often share one IP address. The browser announces the name it wants with SNI (Server Name Indication) at the start of the TLS connection, and the server picks the matching certificate. When no site matches, the server falls back to its default. The nginx documentation explains it: without a match, the browser receives the default server's certificate, whatever site it asked for. The result is often a certificate for another client's domain, or a self-signed one from the hosting panel.
The same symptom appears after a renewal when the new certificate is on disk but the web server was never reloaded, so it still presents the previous one. Our guide on why Let's Encrypt renewals fail covers that trap.
How to confirm. Compare the subject and subjectAltName of what the server sends with what you installed. Also compare the dates: if notAfter is older than your last renewal, the server never loaded the new certificate.
Fix. Check that the site's configuration declares the right name (for example server_name in nginx) and points at the right certificate, then reload. If a name points to this server by mistake, fix the DNS instead.
4. The CDN serves one certificate, the origin another
With a CDN or reverse proxy in front of the site, there are two certificates: the edge certificate that visitors receive from the CDN, and the origin certificate on your server, which only the CDN sees. Cloudflare's documentation describes both. Its Origin CA certificates only encrypt traffic between Cloudflare and your origin server, not traffic from browsers to the origin: if you pause Cloudflare or switch a record to DNS-only, visitors connect to the origin directly and may see untrusted certificate errors.
The reverse also happens. The edge certificate is fine, but the origin certificate expires or does not match. In Cloudflare's Full (strict) mode, visitors then get error 526, which Cloudflare documents as being unable to validate the origin's certificate.
How to confirm. Test the public name normally (that is the edge), then test the origin by connecting to its IP address with the site's name (see the next section). Two different issuers in the output is normal; an origin certificate that a browser does not trust is a problem the day traffic bypasses the CDN.
Fix. Keep a publicly trusted certificate on the origin if the record may ever be switched to DNS-only, and watch the origin certificate's expiry as well as the edge one.
5. An old server or another IP still serves the old certificate
A name can point to several addresses: two IPv4 addresses behind a load balancer, an IPv6 address configured on another machine, a backup server left in the DNS after a migration. Each one serves its own certificate. If one was not updated, some visitors get an error and others do not, depending on which address they reach. That is how "it works for me" and "the client sees a warning" can both be true.
How to confirm. List the addresses, then ask each one for the site's certificate:
host=www.example.com
for ip in $( (dig +short A "$host"; dig +short AAAA "$host") | grep -v '\.$' ); do
case "$ip" in *:*) target="[$ip]:443" ;; *) target="$ip:443" ;; esac
echo "== $ip"
echo | openssl s_client -connect "$target" -servername "$host" 2>/dev/null \
| openssl x509 -noout -enddate -fingerprint -sha256
doneThe grep drops the CNAME names that dig +short can print before the addresses. All addresses should return the same fingerprint, or at least valid dates. With curl, curl -v --resolve www.example.com:443:203.0.113.10 https://www.example.com/ forces one address and shows the certificate it gets.
Fix. Update or remove the stale server, and remove from the DNS any address that no longer belongs to the site. Our guide on orphaned subdomains covers DNS records that outlive the servers they point to.
A quick checklist
- 1Read the error code on the warning page: authority (chain), name, or date.
- 2Run
openssl s_client -servernameagainst the public name and readVerify return code. - 3Check that the name in the address bar is in the
subjectAltNamelist. - 4Compare the dates and issuer with the certificate you installed.
- 5Test every A and AAAA address, and the origin behind the CDN.
- 6Fix, reload, and test again from outside.
How to monitor it
All five causes have one thing in common: they are only visible from outside, on the certificate the server actually sends. A reminder based on the expiry date written in a spreadsheet catches none of them.
Lapsentry connects to each website and reads the certificate it actually serves. Besides the expiry date and the issuer, it reports chain and hostname problems, such as missing intermediates or a certificate for the wrong name, and lets you track www, shop, api or any subdomain separately. For an origin behind a CDN or a specific backup server, the per-address commands above remain the way to check.
Start your 14-day free trial: no card required.
Sources
- nginx, Configuring HTTPS servers (certificate chains, name-based HTTPS servers, SNI).
- Certbot, User guide: where are my certificates? (
fullchain.pem). - Mozilla Security Blog, Preloading Intermediate CA Certificates into Firefox, 13 November 2020.
- IETF, RFC 9525: Service Identity in TLS, section 6.3 (wildcards), and RFC 6066 (Server Name Indication).
- Chrome for Developers, Deprecations and removals in Chrome 58 (commonName matching).
- Chromium, net_error_list.h (CERT_COMMON_NAME_INVALID, CERT_DATE_INVALID, CERT_AUTHORITY_INVALID).
- Cloudflare, Cloudflare origin CA, Edge certificates and Error 526.
FAQ
Why does my browser say the certificate is not valid when it has not expired?
Because expiry is only one check. The browser also verifies that the certificate chains to a trusted authority and that it covers the exact name in the address bar. A missing intermediate certificate or a name that is not covered both trigger a warning on a certificate that is still in date.
What is an incomplete certificate chain?
The server sends the site's certificate without the intermediate certificate that links it to a trusted root. Some browsers fill the gap from a cache or a preloaded list, others do not, which is why the error can appear on one device and not on another.
Does a wildcard certificate cover the bare domain?
No. A wildcard such as *.example.com matches exactly one label, so it covers shop.example.com but not example.com or api.eu.example.com. Add the bare domain to the certificate if the site uses it.
Why do some visitors see the error and others do not?
Usually because the name points to several servers or IP addresses and one of them serves an old or wrong certificate, or because some devices can complete a missing chain on their own. Test each A and AAAA address with the site's name.
Can I use a Cloudflare Origin CA certificate without the Cloudflare proxy?
Not for public visitors. Cloudflare states that Origin CA certificates only encrypt traffic between Cloudflare and your origin. If the record is set to DNS-only or Cloudflare is paused, visitors may see untrusted certificate errors.
How do I see which certificate a server really sends?
Run openssl s_client with the -servername option set to the site's name, then read the subject, issuer, dates and subjectAltName of the certificate returned. Repeat for each IP address if the name has several.
What does NET::ERR_CERT_COMMON_NAME_INVALID mean?
That Chrome received a certificate that does not cover the name you typed. Check the certificate's subjectAltName list: the exact name, or a matching wildcard, must be in it.
More guides