Cybersecurity

How to Fix SSL Certificate Chain Issues

Learn how to identify and resolve missing intermediate certificates that cause trust errors in browsers.

By Inventive HQ Team

A broken certificate chain almost always means one thing: your server is presenting its leaf certificate but failing to send the intermediate CA certificate(s) that link it to a trusted root, so clients that don't cache or fetch intermediates return "unable to verify the first certificate" (OpenSSL verify error 21) even though the certificate itself is valid and unexpired. The fix is not to reissue the certificate — it is to build a fullchain file (leaf first, then each intermediate, in issuing order), point your web server at that file instead of the bare leaf, and reload. In Nginx the ssl_certificate directive must point at the fullchain; in Apache 2.4.8+ you concatenate the chain into the file referenced by SSLCertificateFile.

That's the summary an AI Overview would hand you. What it can't show you is which certificate is missing, why it works in Chrome but breaks in curl and on Android, and the exact command sequence to diagnose and rebuild the chain. Below is the verification flow as an animated diagram, a symptom → cause → fix table you can scan against your own error, the exact OpenSSL and server commands, and a copy-paste checklist.

Prefer to skip straight to the fix? Our free Certificate Chain Builder fetches the missing intermediates and outputs a correctly ordered fullchain you can paste into your config.

How chain verification actually works

A browser or client trusts a fixed set of root CAs baked into its trust store. Your certificate is not signed by a root directly — it is signed by an intermediate CA, which is signed (possibly through more intermediates) by the root. Verification walks this chain from your leaf certificate upward until it reaches a certificate it already trusts. If any link is missing from what the server sends, the walk stops and trust fails.

Certificate chain of trust: leaf to intermediate to root The client verifies the server's leaf certificate against an intermediate CA, which chains up to a trusted root CA in the client's trust store. A missing intermediate breaks the walk. Leaf certificate your-domain.com (depth 0) Intermediate CA (depth 1) — often missing Root CA in client trust store (depth 2)

signed by signed by

Verification walks leaf → root If server omits this, the walk stops here

The critical point: the server is responsible for sending the leaf plus every intermediate. The root is already in the client's trust store, so you do not (and should not) include it. When people say "the chain is broken," they almost always mean the intermediate at depth 1 was never sent.

Diagnose it in one command

Run this from any machine that can reach the host. It opens a TLS connection and prints what the server actually sent:

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

Read the top of the output:

  • Certificate chain section lists each cert with s: (subject) and i: (issuer). A healthy chain shows depth 0 (your domain), depth 1 (intermediate), and often depth 2. If you only see 0 s:..., the intermediate is missing.
  • Verify return code: 0 (ok) means the chain validated. Anything else — especially 21 (unable to verify the first certificate) or 20 (unable to get local issuer certificate) — points at a missing or wrong intermediate.

To see exactly which issuer you need to chase down:

openssl x509 -in server.crt -noout -issuer -subject

The issuer= line names the intermediate CA that signed your certificate. That is the cert you must obtain and add to the chain.

Symptom → cause → fix

Match your exact error to the row:

SymptomRoot causeFix
unable to verify the first certificate (verify error 21)Intermediate cert(s) not sent by serverBuild a fullchain (leaf + intermediate) and point the server at it
unable to get local issuer certificate (verify error 20) in curl/OpenSSLSame missing-intermediate problem, seen by a client that won't AIA-fetchServe the full chain; do not rely on client-side fetching
Works in Chrome, fails on Android / curl / Java / PostmanChrome cached the intermediate or fetched it via AIA; other clients didn'tServe the full chain so no client has to fetch anything
Chain complete but still verify errorCertificates in wrong order, or wrong (cross-signed) intermediateReorder leaf → intermediate → root; verify each i: matches the next s:
certificate has expired on a cert you didn't touchAn intermediate expired (e.g. the 2021 Let's Encrypt / DST Root event)Replace the intermediate with the current one from your CA
SSL Labs shows "Extra download" or "Chain issues: Incomplete"Leaf served alone, intermediate missingRebuild fullchain; re-test
SSL Labs flags "Contains anchor"Root CA included in the served chainRemove the root; serve only leaf + intermediate(s)
Advertisement

Fix it: build the fullchain

Order is non-negotiable — leaf first, then each intermediate in issuing order, root omitted:

# server.crt = your leaf, intermediate.crt = the CA that signed it
cat server.crt intermediate.crt > fullchain.crt

If your CA gave you a bundle with several intermediates, concatenate them from the one that signed your leaf up toward (but not including) the root. Verify the assembled file locally before deploying:

openssl verify -untrusted intermediate.crt server.crt
# expected: server.crt: OK

Nginx

Nginx has no separate chain directive — ssl_certificate must point at the fullchain, not the bare leaf:

server {
    listen 443 ssl;
    ssl_certificate     /etc/ssl/fullchain.crt;   # leaf + intermediate(s)
    ssl_certificate_key /etc/ssl/private.key;
}
nginx -t && nginx -s reload

Apache

On Apache 2.4.8 and newer, SSLCertificateChainFile is deprecated — concatenate the chain into the file referenced by SSLCertificateFile:

SSLCertificateFile    /etc/ssl/fullchain.crt   # leaf + intermediate(s)
SSLCertificateKeyFile /etc/ssl/private.key
apachectl configtest && systemctl reload apache2

Why "it works in Chrome" is a trap

Chrome on Windows and macOS can fetch a missing intermediate through the AIA (Authority Information Access) extension — a URL embedded in your certificate that points at the issuing CA's cert. Chrome may also have cached the intermediate from a previous site. That masks a broken chain during your own testing.

Same broken chain, different client outcomes A server missing its intermediate succeeds in Chrome via AIA fetching or caching, but fails in curl, Android, and Java clients that require the full chain. One misconfigured server, sending leaf only Server: leaf only intermediate missing Chrome (desktop) AIA-fetches / caches ✓ appears to work curl / OpenSSL no AIA fetch ✗ verify error 20/21 Android / Java / API require full chain ✗ handshake fails

The rule follows directly: never rely on AIA fetching or browser caching. Serve the complete chain and every client — mobile apps, curl, Java, monitoring probes, other browsers — verifies without a network round trip. AIA fetching also adds latency and breaks behind egress firewalls.

Verification checklist

Work top to bottom; each step is copy-paste-able:

  1. Confirm the symptom. openssl s_client -connect example.com:443 -servername example.com < /dev/null — read Verify return code.
  2. Identify the missing issuer. openssl x509 -in server.crt -noout -issuer — note the CA name.
  3. Download the correct intermediate from your CA's repository (DigiCert, Sectigo, Let's Encrypt, GlobalSign all publish them). Match the exact issuer from step 2 — cross-signed CAs publish more than one.
  4. Build the fullchain in order: cat server.crt intermediate.crt > fullchain.crt (root omitted).
  5. Validate locally: openssl verify -untrusted intermediate.crt server.crtOK.
  6. Point the server at the fullchain (Nginx ssl_certificate; Apache SSLCertificateFile) and reload.
  7. Re-test from a non-caching client: curl -vI https://example.com should not report a certificate problem.
  8. Confirm externally with SSL Labs — you want "Chain issues: None" and grade A.

The Certificate Chain Builder automates steps 3–5: it reads your leaf, fetches the matching intermediate from the CA, and hands you a correctly ordered fullchain. Pair it with the SSL Checker to confirm the deployed result.

The bottom line

Chain errors are a deployment problem, not a certificate problem. Ninety percent of them are a missing intermediate at depth 1; the rest are wrong order, an expired intermediate, or an accidentally included root. Diagnose with one openssl s_client call, rebuild the fullchain leaf-first, point your server at it, and verify from a client that won't quietly paper over the gap. Do that and the certificate you already paid for will validate everywhere — not just in the one browser you happened to test.

Frequently Asked Questions

What is a certificate chain and why does it matter?

A certificate chain (or chain of trust) links your server certificate to a trusted root CA through intermediate certificates. Browsers trust root CAs but your certificate is signed by an intermediate CA, which is signed by the root. If the chain is incomplete (missing intermediates), browsers can't verify trust and show errors like "unable to verify the first certificate" even though your certificate is valid.

How do I identify a missing intermediate certificate?

Use OpenSSL to check the chain: openssl s_client -connect domain.com:443 -servername domain.com. Look for "unable to verify the first certificate" or "verify error:num=21:unable to verify the first certificate". The output shows which certificates were received—if you only see your leaf certificate (depth=0) without intermediates, the chain is incomplete.

Where do I get the intermediate certificate for my SSL certificate?

Download from your Certificate Authority's repository. DigiCert, Sectigo, Let's Encrypt, and other CAs publish intermediate certificates on their websites. Search for "[CA name] intermediate certificate" or check the CA's documentation. You can also extract the issuer from your certificate (openssl x509 -in cert.pem -noout -issuer) and search for that CA's intermediate.

How do I combine certificates into a proper chain file?

Create a fullchain file by concatenating certificates in order from leaf to root (but usually excluding the root): cat server.crt intermediate.crt > fullchain.crt. The order matters—your server certificate first, then intermediate(s). In Nginx, use ssl_certificate with the fullchain file. In Apache, use SSLCertificateFile for the server cert and SSLCertificateChainFile for intermediates.

Why does my certificate work in Chrome but not in other browsers or mobile?

Chrome and some browsers cache intermediate certificates from previous visits or use AIA (Authority Information Access) to fetch missing intermediates automatically. Other browsers, mobile devices, and API clients don't do this—they require the server to provide the complete chain. Always serve the full chain; don't rely on browser caching.

How do I verify my certificate chain is correctly configured?

Use SSL Labs (ssllabs.com/ssltest) for comprehensive testing—it shows chain issues clearly. Alternatively, use OpenSSL: openssl s_client -connect domain.com:443 -servername domain.com | grep -E "verify|depth". You should see "Verify return code: 0 (ok)" and certificates at depth 0, 1, and possibly 2. Our SSL Checker tool also validates chain configuration.

What is AIA fetching and should I rely on it?

AIA (Authority Information Access) is a certificate extension containing URLs where missing intermediate certificates can be downloaded. Some clients fetch intermediates via AIA when not provided by the server. However, this adds latency, fails behind firewalls, and many clients (including curl, older Java, mobile apps) don't support it. Never rely on AIA—always serve the complete chain.

My chain is complete but I still get errors—what else could be wrong?

Check for: (1) Wrong order—certificates must be leaf → intermediate(s) → optional root, (2) Expired intermediate certificate, (3) Cross-signed intermediates—use the correct one for your certificate's issuer, (4) Root CA included when it shouldn't be (wastes bandwidth, some clients reject), (5) Wrong intermediate for your certificate—verify the issuer matches.

How do I fix certificate chain issues on Nginx?

Create a fullchain file combining your certificate and intermediate(s): cat server.crt intermediate.crt > fullchain.crt. In nginx.conf, use ssl_certificate /path/to/fullchain.crt; and ssl_certificate_key /path/to/private.key;. Reload nginx with nginx -t && nginx -s reload. Verify with openssl s_client -connect localhost:443.

How do I fix certificate chain issues on Apache?

In Apache, configure: SSLCertificateFile /path/to/server.crt, SSLCertificateKeyFile /path/to/private.key, SSLCertificateChainFile /path/to/intermediate.crt (or fullchain in newer Apache versions). Alternatively, use SSLCACertificateFile for the chain. Restart Apache with systemctl restart apache2 or apachectl -k restart. Test with openssl or SSL Labs.

SSL chaincertificate trustintermediate certificatesSSL troubleshooting