How HTTP Works

Debug guide · you're seeing

  • Your connection is not private. Attackers might be trying to steal your information from example.com (for example, passwords, messages, or credit cards). NET::ERR_CERT_COMMON_NAME_INVALID
  • NET::ERR_CERT_AUTHORITY_INVALID
  • NET::ERR_CERT_DATE_INVALID
  • Warning: Potential Security Risk Ahead. SSL_ERROR_BAD_CERT_DOMAIN
  • curl: (60) SSL: no alternative certificate subject name matches target hostname 'example.com'
  • curl: (60) SSL: no alternative certificate subject name matches target host name 'example.com'

NET::ERR_CERT_COMMON_NAME_INVALID: Fix the Name Mismatch

Fix NET::ERR_CERT_COMMON_NAME_INVALID and related ERR_CERT errors: SAN vs CN, wildcard limits, missing SNI, expired or incomplete chains, with openssl checks.

Reviewed 6 min readintermediate5 sourcesTry itMarkdown
On this page

TL;DR: The server presented a certificate whose Subject Alternative Names do not include the hostname you typed (Chrome ignores the Common Name). Run openssl s_client -connect HOST:443 -servername HOST and compare the SANs with the URL. The usual causes are a missing www or apex name, a wildcard used one level too deep, and a server returning its default certificate because the client sent no SNI (connecting by IP).

What it means

This is not an HTTP error. The failure happens during the TLS handshake, before any HTTP request is sent, so there is no status code, no Server header and nothing in your web server’s access log. The browser compares the hostname in the URL with the names in the certificate (RFC 9110 section 4.3.4 defers to the RFC 6125 rules) and aborts on a mismatch:

Your connection is not private
Attackers might be trying to steal your information from example.com (for example, passwords, messages, or credit cards).
NET::ERR_CERT_COMMON_NAME_INVALID

The same fault in other clients:

Firefox:  SSL_ERROR_BAD_CERT_DOMAIN
Safari:   This Connection Is Not Private
curl:     curl: (60) SSL: no alternative certificate subject name matches target hostname 'example.com'
          (older curl: "target host name")
openssl:  Verification error: hostname mismatch

“Common name” refers to the legacy CN field in the certificate subject. Chrome has ignored it since version 58. RFC 6125 section 6.4.4 lets a client fall back to the CN only when the certificate has no DNS SAN at all, and browsers dropped even that. A certificate that says CN = example.com can therefore still fail: the SAN list does not contain it.

Who sent it?

The browser decided, from the certificate it was shown. The question is which server showed a certificate for the wrong names, and the answer is whoever terminates TLS for that hostname: your web server, a load balancer, a CDN or an ingress controller. Look at the real certificate:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
subject=CN = example.org
issuer=C = US, O = Let's Encrypt, CN = R11
notBefore=Sep  1 08:00:00 2026 GMT
notAfter=Nov 30 08:00:00 2026 GMT
X509v3 Subject Alternative Name:
    DNS:example.org, DNS:www.example.org

Here the certificate is valid but for example.org, not example.com. Now repeat without -servername to see the server’s default certificate:

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

If the two differ, the server picks the certificate by SNI (Server Name Indication, RFC 6066 section 3), and the hostname you are testing is not configured on it, so it falls through to the default. If you are connecting by IP, add -servername with the real hostname; browsers never send an IP address as SNI.

Identify the terminating layer with the response headers you can still get, using -k only for diagnosis:

curl -skI https://example.com/ | grep -iE '^(server|via|cf-ray|x-amz|x-served-by)'

Fix it, in order of likelihood

  1. The certificate does not list the hostname. Reissue it with every name users type, including example.com and www.example.com.
  2. A wildcard is being used for the wrong level. *.example.com does not cover example.com or a.b.example.com.
  3. The server has no certificate for that name and falls back to a default (new vhost without TLS, new domain added to a CDN or ALB without a certificate).
  4. DNS points to the wrong server, for example a stale A record sending traffic to the old host that still has the old certificate.
  5. An internal or private hostname uses a public certificate, or the reverse.

Let’s Encrypt with certbot

# Issue one certificate covering both names
certbot --nginx -d example.com -d www.example.com

# Add a name to an existing certificate
certbot --nginx --expand -d example.com -d www.example.com -d api.example.com

# Check what is installed
certbot certificates

Wildcards require the DNS-01 challenge (certbot certonly --dns-cloudflare -d example.com -d '*.example.com' with the matching plugin).

nginx: serve the right certificate, and refuse unknown names

server {
    listen 443 ssl;
    http2 on;
    server_name example.com www.example.com;

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

# Default server: refuse the handshake for hostnames you do not host (nginx 1.19.4+)
server {
    listen 443 ssl default_server;
    ssl_reject_handshake on;
}

Without a default server that rejects, nginx hands unknown names the first server block’s certificate, which is exactly how “wrong certificate” errors reach visitors.

Kubernetes with cert-manager

Every hostname in the Ingress needs to be listed under tls.hosts and in the Certificate’s dnsNames:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com
spec:
  secretName: example-com-tls
  dnsNames:
    - example.com
    - www.example.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

AWS ACM, ALB and CloudFront

The certificate attached to the listener or distribution must list the alternate domain name you are serving. For CloudFront, the certificate must be in us-east-1, and the distribution’s alternate domain names (CNAMEs) must be covered by it. On an ALB listener you can attach several certificates and the ALB picks one by SNI.

The other ERR_CERT errors

NET::ERR_CERT_AUTHORITY_INVALID

The browser cannot chain the certificate to a trusted root. Causes, most common first:

  • The server sends only the leaf certificate and not the intermediates. Many desktop browsers can fetch missing intermediates, but Android and curl often cannot, so it works for you and fails elsewhere. Serve fullchain.pem, not cert.pem.
  • Self-signed or private-CA certificate that the device does not trust.
  • A corporate proxy that inspects TLS and re-signs certificates with a company root the browser or OS does not have installed.
echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null | grep -E 'verify|depth|s:|i:'

Look for verify error:num=20:unable to get local issuer certificate or num=21:unable to verify the first certificate. Both point to a missing intermediate. Also check Verify return code at the end of the output.

NET::ERR_CERT_DATE_INVALID

The certificate is expired or not yet valid, or the visitor’s clock is wrong. Check dates server-side:

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

# Exit status 0 if the cert is still valid 30 days from now, 1 if not
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -checkend $((30*24*3600))

If the server’s dates are fine and only some devices fail, the device clock is the problem. If issuance is automated, check the renewal job (certbot renew --dry-run) and that nginx was reloaded after renewal, since nginx loads certificates at start or reload and does not notice a replaced file.

Cloudflare in front of your origin adds two related errors for the origin leg: 525 (TLS handshake failed) and 526 (invalid origin certificate when SSL mode is Full strict). They mean your origin’s certificate has one of the problems above.

Reproduce and verify

# Hostname verification as a client would do it (exit code 0 means OK)
curl -sS -o /dev/null -w '%{http_code} ssl_verify=%{ssl_verify_result}\n' https://example.com/

# Verify the hostname explicitly with openssl (-verify_hostname needs OpenSSL 1.1.0+)
echo | openssl s_client -connect example.com:443 -servername example.com -verify_hostname example.com 2>/dev/null \
  | grep -E 'Verification|Verify return code'

A ssl_verify of 0 and Verify return code: 0 (ok) mean the chain and the hostname match. Test every name (apex, www, API subdomain) and also from a second network, because a split-horizon DNS or a CDN edge can serve a different certificate than the one you tested from.

  • HTTPS and TLS explains the handshake, chains of trust and what a certificate vouches for.
  • Strict-Transport-Security removes the click-through option for certificate errors on hosts that sent it.
  • Mixed content is the failure you meet next when the certificate works but the page still loads HTTP resources.
  • Too many redirects often appears together with TLS offload misconfiguration.
  • ERR_SSL_PROTOCOL_ERROR is the failure one step earlier, when the handshake breaks before any certificate is checked.
  • ERR_CERT_DATE_INVALID: expired certificates, renewals that never got deployed, expired intermediates and wrong client clocks.

Frequently asked questions

Why does Chrome say COMMON_NAME_INVALID when the certificate has the right Common Name?

Chrome has ignored the Common Name field for hostname matching since version 58 and checks only the Subject Alternative Name (SAN) extension. A certificate whose CN is example.com but whose SAN list lacks example.com fails with this error. The error name is a historical leftover; read it as "no SAN entry matches the hostname".

Does a wildcard certificate cover the bare domain?

No. *.example.com matches www.example.com and api.example.com, but not example.com itself and not a.b.example.com, because a wildcard covers exactly one DNS label. Add example.com as its own SAN entry; most CAs include it in wildcard orders.

Why do I get the wrong certificate only on some requests or only by IP?

A server hosting several names selects the certificate from the SNI value the client sends in the TLS handshake. Visiting by IP address sends no hostname, so the server returns its default certificate, which usually belongs to a different site. An old client without SNI support has the same effect.

What is the difference between ERR_CERT_COMMON_NAME_INVALID, AUTHORITY_INVALID and DATE_INVALID?

COMMON_NAME_INVALID means the certificate is valid but not for this hostname. AUTHORITY_INVALID means the browser cannot build a chain to a trusted root: a self-signed certificate, a missing intermediate, or a corporate TLS-inspection proxy. DATE_INVALID means the certificate is expired, not yet valid, or the device clock is wrong.

Can I bypass this error on a site with HSTS?

No. Once a host has sent Strict-Transport-Security, browsers remove the "Proceed anyway" option for certificate errors on that host, so the certificate must actually be fixed. This is deliberate, because it stops users from clicking through an active interception.

Sources

  1. MDN: Transport Layer Security (TLS)developer.mozilla.org
  2. RFC 9110 Section 4.3.4: HTTPS Certificate Verificationrfc-editor.org
  3. RFC 6125: Representation and Verification of Domain-Based Application Service Identityrfc-editor.org
  4. RFC 6066 Section 3: Server Name Indicationrfc-editor.org
  5. Let's Encrypt: Chain of Trustletsencrypt.org

Keep going

Browse /search