What Chrome is telling you

A certificate is only worth something if it’s signed by someone the browser already trusts. Chrome checks this by building a chain: your site’s certificate (the leaf) was signed by an intermediate, which was signed by a root, and that root must be in the trust store Chrome uses.

NET::ERR_CERT_AUTHORITY_INVALID means that chain didn’t end at a trusted root. The certificate may be perfectly valid in every other respect: right name, not expired. Chrome just doesn’t know whether to believe whoever signed it.

The full-page warning reads “Your connection is not private”. Other browsers report the same failure differently: Firefox says SEC_ERROR_UNKNOWN_ISSUER, or MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT for a self-signed certificate, and Safari says the certificate is not trusted.

First, look at the issuer

The issuer name tells you which case you’re in, so it’s worth the ten seconds. In Chrome, click “Not secure” in the address bar → “Certificate is not valid”, and look at “Issued By”. Or from a terminal:

openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null 2>/dev/null \
  | grep -E '^ +([0-9]+ )?[si]:'
What you see as issuerWhat it usually means
The same as the subject (the site’s own name)Self-signed certificate
A public CA (Let’s Encrypt, DigiCert, Sectigo, GlobalSign…), only one certificate in the chainMissing intermediate on the server
Your antivirus product, your company, a firewall or proxy vendorSomething on your side is intercepting TLS
Kubernetes Ingress Controller Fake Certificate, TRAEFIK DEFAULT CERT, your hosting company’s name, a router or NAS modelA default placeholder certificate; the real one isn’t configured
A name starting with (STAGING)A Let’s Encrypt test certificate
Cloudflare Origin somethingA Cloudflare Origin CA certificate reached the browser directly
A company’s internal CAPrivate PKI, root not installed on this device

Then answer one more question: does the site fail everywhere, or only for you? Run the SSL check, which connects from a server in Seoul and verifies the chain against the standard Mozilla root list. If it reports the chain as OK and you still get the error, the problem is on your side.

If you’re a visitor

When the error shows up on many sites at once, or only on one network or one device, the server isn’t the problem.

Antivirus HTTPS scanning. Several antivirus products decrypt HTTPS to inspect it, re-signing each site with their own root certificate. Normally the installer adds that root to your trust store and you never notice. When the installation is broken, or you use Firefox (which keeps its own store), every HTTPS site fails with the antivirus vendor as issuer. Turn off the HTTPS/SSL scanning option in the antivirus settings, or repair the installation.

Corporate inspection proxies. On a company laptop the company root is installed and everything works. On a personal phone on the office Wi-Fi it isn’t, so everything fails. That’s a policy question for IT, not something to work around.

Captive portals. Hotel, airport and café Wi-Fi intercept your first request to show a login page. Open any http:// page (for example http://neverssl.com) to get the login screen, log in, then retry.

Old devices. A device that hasn’t had updates in years has an old root store. Newer CAs or newer roots aren’t in it. Let’s Encrypt certificates, for example, chain to ISRG Root X1, which Android only added in version 7.1.1; the cross-signed chain that used to cover older Android versions has expired. The only real fix is an updated OS or a browser that brings its own root store; Firefox does, and so does Chrome on desktop.

A wrong system clock usually gives a different error, NET::ERR_CERT_DATE_INVALID, but it’s cheap to check while you’re at it.

Don’t click through on a public site. This warning looks exactly like what you’d see if someone were intercepting the connection. If the domain uses HSTS, Chrome won’t offer the option anyway.

If you run the site

1. The server doesn’t send the intermediate

The leaf is from a public CA, but the server sends it alone. Desktop Chrome often hides this by downloading the intermediate itself from the AIA URL in the certificate. You see AUTHORITY_INVALID in Chrome only when that download fails, but curl, Java, Python and Android apps fail every time.

Fix: configure the full chain (fullchain.pem with certbot, or your certificate plus the CA bundle, leaf first). Check with:

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

You want at least two certificates in “Certificate chain” and Verify return code: 0 (ok). 21 (unable to verify the first certificate) means the intermediate is missing. File layouts, ordering and key-mismatch problems are covered in Incomplete SSL chain or hostname mismatch.

2. A self-signed or placeholder certificate is being served

Usually nobody chose a self-signed certificate. A component falls back to its built-in default because the real certificate isn’t configured for this name:

  • ingress-nginx serves Kubernetes Ingress Controller Fake Certificate when an Ingress has no matching TLS secret, the secret is in another namespace, or the hosts under tls: don’t include this name.
  • Traefik serves TRAEFIK DEFAULT CERT when no router with TLS matches the hostname, or certificate resolution (ACME) failed.
  • Hosting control panels often serve a self-signed placeholder for a domain until SSL is enabled for it.
  • Appliances (routers, NAS, printers, management interfaces) ship with self-signed certificates.

Fix: configure the real certificate for this hostname, then check the logs of the component that fell back. For Kubernetes, kubectl describe ingress <name> and the controller’s logs say why it couldn’t use your secret. If you use cert-manager, kubectl get certificate shows whether issuance actually succeeded.

For local development, don’t fight the warning: mkcert creates a local CA, installs it in your system and browser trust stores, and issues certificates for localhost or any name you like.

3. A Let’s Encrypt staging certificate went to production

certbot’s --staging (or --test-cert) and the ACME staging endpoint in other clients issue certificates from a CA that no browser trusts, deliberately. The issuer begins with (STAGING). Easy to leave in place after testing a setup.

Fix: issue against the production endpoint. With certbot, run the same command without --staging, adding --force-renewal if it insists the current certificate is still valid. Then reload the web server.

4. A Cloudflare Origin CA certificate is reaching browsers

Origin CA certificates are free and long-lived, but only Cloudflare trusts them. That’s fine as long as visitors only ever see Cloudflare’s edge certificate. It breaks when:

  • the DNS record is switched from Proxied to DNS only, or
  • visitors reach the origin directly by IP or through another hostname.

Fix: keep the record proxied, or put a publicly trusted certificate (Let’s Encrypt works fine) on the origin for any name that’s served directly. See Cloudflare SSL modes for how the two certificate legs relate.

5. A private CA on a public-facing name

Internal CAs (Active Directory Certificate Services, HashiCorp Vault, step-ca, an OpenSSL CA someone made years ago) are fine for internal services, as long as every client trusts the root. If the same name is reachable by outsiders or unmanaged devices, they’ll get this error.

Fix: either use a public certificate for that name, or install the root on every client that needs it:

# Debian / Ubuntu
sudo cp corp-root.crt /usr/local/share/ca-certificates/corp-root.crt
sudo update-ca-certificates

# RHEL / Fedora / Rocky
sudo cp corp-root.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

# macOS
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain corp-root.crt

# Windows (admin prompt)
certutil -addstore -f Root corp-root.crt

The OS store covers Chrome, Edge and Safari. Several other clients ignore it:

  • Firefox keeps its own store. Import the root under Settings → Certificates, or let it trust enterprise roots from the OS with security.enterprise_roots.enabled.
  • Java uses its own cacerts: keytool -importcert -cacerts -alias corp-root -file corp-root.crt.
  • Python requests uses the certifi bundle: point REQUESTS_CA_BUNDLE at a file containing your root.
  • Node.js uses a bundled list: set NODE_EXTRA_CA_CERTS=/path/to/corp-root.crt.
  • Containers need the root installed in the image, not just on the host.

6. The CA isn’t trusted by this browser any more, or not yet

Browsers occasionally remove a CA from their root programs after compliance problems, and certificates it issued afterwards stop working in those browsers. At the other end, a brand-new root takes years to reach every device. If the SSL check shows a valid chain but a particular browser or OS still refuses it, compare the root at the top of your chain with that platform’s current root list, and if necessary switch to a CA whose roots it carries.

After the fix

  • openssl s_client -showcerts shows the full chain and Verify return code: 0 (ok).
  • The SSL check reports the chain as OK. If it still says Untrusted, the reason next to it says which case is left: “self-signed certificate”, “untrusted root in chain” or “incomplete chain or unknown issuer”. The check verifies the chain but doesn’t check revocation.
  • Test with something strict, not just Chrome: curl -sSI https://www.example.com/ is enough.
  • Then use the HTTP check to confirm the HTTPS response and redirects behave as expected.

Check your own domain now

Free, no sign-up. Runs the exact check this guide describes and shows what to fix.