high8 min readLast updated May 27, 2026

TLS Certificate Chain Issues: Incomplete Chains, Wrong Intermediates, and How to Fix Them

Incomplete TLS certificate chains cause trust errors in some browsers but not others. Learn how to diagnose chain problems and fix them on Nginx and Apache.

What is a certificate chain?

When your browser connects to a website over HTTPS, it needs to verify that the server's TLS certificate is trustworthy. It does this by following a chain of trust:

  1. Leaf certificate -- the certificate issued specifically for your domain (e.g., www.yourcompany.com)
  2. Intermediate certificate(s) -- one or more certificates issued by the root CA to a subordinate CA, which in turn issued your leaf certificate
  3. Root certificate -- a self-signed certificate from a trusted root certificate authority (CA), pre-installed in browsers and operating systems

The browser starts at the leaf, follows the chain through the intermediates, and verifies it ends at a trusted root. If any link in this chain is missing, broken, or expired, the browser cannot verify trust -- and the user sees an error.

What happens when the chain is incomplete

An incomplete certificate chain is one of the most frustrating TLS issues because it manifests inconsistently:

  • Desktop Chrome and Firefox might work fine -- they have a feature called AIA (Authority Information Access) fetching that can download missing intermediates automatically
  • Mobile browsers may show a trust error
  • Older Android devices may reject the connection entirely
  • Curl and wget will fail with a verification error
  • API clients and webhooks will refuse to connect
  • Automated monitoring tools may report your site as down

This inconsistency makes the problem hard to catch -- your team tests in Chrome, everything looks fine, but a significant portion of users are seeing errors.

Common certificate chain issues

Missing intermediate certificate

The most common problem. Your web server sends only the leaf certificate but not the intermediate(s). The browser cannot build the chain to a trusted root.

# Check if intermediates are being sent
openssl s_client -connect yourcompany.com:443 -showcerts </dev/null 2>/dev/null

# Look at the output -- you should see multiple certificates
# Certificate #0 = your leaf certificate
# Certificate #1 = intermediate certificate
# If only #0 is present, the intermediate is missing

Wrong intermediate certificate

Your server sends an intermediate, but it is the wrong one -- perhaps from a different CA or a different product line within the same CA. The chain does not connect to a trusted root.

Expired intermediate certificate

Intermediate certificates have their own expiry dates. If an intermediate expires and you do not update it, the chain breaks even though your leaf certificate is still valid. This is particularly sneaky because certificate expiry monitoring often only checks the leaf certificate.

Wrong certificate order

The chain must be in order: leaf first, then intermediate(s), with the root optionally last. If the certificates are concatenated in the wrong order, some clients fail to validate the chain.

# CORRECT order in the certificate file:
-----BEGIN CERTIFICATE-----
(Leaf certificate for yourcompany.com)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate)
-----END CERTIFICATE-----

# WRONG order:
-----BEGIN CERTIFICATE-----
(Intermediate certificate)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Leaf certificate for yourcompany.com)
-----END CERTIFICATE-----

Including the root certificate

Including the root certificate in the chain is not harmful but is unnecessary -- browsers already have root certificates in their trust store. It adds a small amount of overhead to the TLS handshake.

Cross-signed certificate confusion

Some CAs use cross-signed intermediates for backward compatibility. For example, Let's Encrypt's ISRG Root X1 was cross-signed by IdenTrust's DST Root CA X3. When the cross-signed root expired in September 2021, older devices that relied on it broke. If your server sends the cross-signed chain instead of the direct chain, some clients may have trouble.

How to diagnose chain problems

SSL Labs Server Test

SSL Labs is the most comprehensive tool. It shows:

  • The full certificate chain your server sends
  • Whether the chain is complete
  • Whether the order is correct
  • Trust status across different platforms (Apple, Android, Java, Mozilla, Windows)
  • A clear "Chain issues" section highlighting problems

Using openssl

# Show all certificates in the chain
openssl s_client -connect yourcompany.com:443 -showcerts </dev/null 2>/dev/null

# Verify the chain explicitly
openssl s_client -connect yourcompany.com:443 </dev/null 2>/dev/null | openssl x509 -noout -issuer -subject

# Full verification with system trust store
openssl s_client -connect yourcompany.com:443 -verify_return_error </dev/null 2>&1

If you see verify error:num=21:unable to verify the first certificate, the intermediate is missing.

What's My Chain Cert

whatsmychaincert.com is a purpose-built tool for diagnosing and fixing chain issues. Enter your domain, and it tells you exactly which intermediate you need and provides the correct chain file for download.

Using curl

# curl is strict about certificate chains -- it will fail if the chain is broken
curl -vI https://yourcompany.com 2>&1 | grep -E "SSL certificate|verify"

# If you see "SSL certificate problem: unable to get local issuer certificate"
# the chain is incomplete

How to fix certificate chain issues

Step 1: Identify the correct intermediate

Your CA's documentation or website will have the correct intermediate certificate for download. Common sources:

Or use whatsmychaincert.com to automatically identify and provide the correct intermediate.

Step 2: Create the correct chain file

Concatenate your leaf certificate and intermediate(s) in the correct order:

cat your-domain-cert.pem intermediate-cert.pem > fullchain.pem

# Verify the chain file
openssl verify -untrusted fullchain.pem your-domain-cert.pem

Fixing on Nginx

In Nginx, the ssl_certificate directive must point to a file containing the leaf certificate followed by the intermediate(s):

server {
    listen 443 ssl;
    server_name yourcompany.com;

    # This file must contain: leaf cert + intermediate cert(s)
    ssl_certificate /etc/ssl/certs/yourcompany-fullchain.pem;

    # This is your private key (leaf only)
    ssl_certificate_key /etc/ssl/private/yourcompany.key;
}

Create the full chain file:

# Concatenate leaf + intermediate
cat /etc/ssl/certs/yourcompany.pem /etc/ssl/certs/intermediate.pem > /etc/ssl/certs/yourcompany-fullchain.pem

# Test and reload
sudo nginx -t
sudo systemctl reload nginx

Fixing on Apache

Apache 2.4.8+ supports a single combined file (like Nginx), but you can also use the SSLCertificateChainFile directive for the intermediates separately:

# Option 1: Combined file (Apache 2.4.8+)
SSLCertificateFile /etc/ssl/certs/yourcompany-fullchain.pem
SSLCertificateKeyFile /etc/ssl/private/yourcompany.key

# Option 2: Separate files
SSLCertificateFile /etc/ssl/certs/yourcompany.pem
SSLCertificateKeyFile /etc/ssl/private/yourcompany.key
SSLCertificateChainFile /etc/ssl/certs/intermediate.pem

Test and reload:

sudo apachectl configtest
sudo systemctl reload apache2

Why Let's Encrypt usually gets this right

If you use certbot or another ACME client with Let's Encrypt, the fullchain.pem file it generates already includes the leaf certificate and the correct intermediate. Nginx and Apache should point to fullchain.pem, not cert.pem:

# CORRECT -- fullchain includes intermediates
ssl_certificate /etc/letsencrypt/live/yourcompany.com/fullchain.pem;

# WRONG -- cert.pem is the leaf only, missing intermediates
ssl_certificate /etc/letsencrypt/live/yourcompany.com/cert.pem;

When Let's Encrypt chains go wrong

Chain issues with Let's Encrypt typically happen when:

  • Someone manually points to cert.pem instead of fullchain.pem
  • The ACME client is outdated and generates an old chain
  • The server has cached an old intermediate after a chain change
  • Older Android devices (before 7.1.1) do not trust the ISRG Root X1 directly

Verify the fix

After updating your certificate chain:

# Quick check -- should show the full chain
openssl s_client -connect yourcompany.com:443 -showcerts </dev/null 2>/dev/null | grep -E "s:|i:"

# Strict verification -- should succeed with no errors
curl -vI https://yourcompany.com 2>&1 | grep "SSL certificate verify"

Then run SSL Labs again -- your chain issues section should be clean, and the trust section should show "trusted" across all platforms.

For related TLS topics, see our guides on expired TLS certificates and weak TLS cipher suites. If you use wildcard certificates, chain issues can affect every subdomain at once -- another reason to get them right.

How SurfaceScan helps

SurfaceScan validates the full TLS certificate chain on every HTTPS-enabled host during each scan. It detects missing intermediates, wrong certificate order, expired intermediates, and cross-signing issues -- including cases where the chain works in Chrome but fails on mobile or in API clients. Chain issues are flagged in the TLS Certificates section with the specific problem identified and the correct intermediate certificate referenced, so your team can fix the issue in minutes rather than debugging intermittent trust errors reported by users.

Related articles