SSL diagnostic output showing certificate chain verification error with missing intermediate certificate and correct chain structure diagram
# developer tools# website monitoring

Incomplete Certificate Chain Fix: Causes and Solutions

Your SSL certificate is valid and hasn't expired, but browsers are showing a security warning. The most likely culprit: an incomplete certificate chain. Your server is sending your domain certificate but not the intermediate certificates that connect it to a trusted root.


How Certificate Chains Work

Certificate authorities don't sign your certificate directly with their root certificate — roots are kept offline for security. Instead, they use intermediate certificates that chain from the root to your certificate:

Root CA (trusted by browsers)
  └── Intermediate CA
        └── Your domain certificate

Browsers trust the root. When they receive your certificate, they need to trace a path from your certificate back to a trusted root. If the intermediate is missing, the chain breaks.

Most modern browsers attempt to fetch missing intermediates automatically (AIA chasing), which is why the error is intermittent in some browsers and consistent in others. See why HTTPS works in one browser but fails in another for the full explanation of browser-specific behaviour.

Mobile browsers, older browsers, and strict TLS clients (like curl with --verify-peer) don't do AIA chasing — they fail immediately if intermediates are missing.


Diagnosing an Incomplete Chain

# Check the chain being served by your server
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com

# Look in the output for "Certificate chain"
# A complete chain shows 2+ certificates (leaf + at least one intermediate)
# An incomplete chain shows only 1 certificate (just the leaf)

# More targeted check
echo | openssl s_client -connect yourdomain.com:443 2>/dev/null \
  | openssl x509 -noout -text | grep -A2 "Issuer:"

You can also use SSL Labs' server test — it explicitly reports "Chain issues: Incomplete" if intermediates are missing, and grades you down for it.

A common field to check is the Authority Information Access (AIA) extension in the certificate itself:

echo | openssl s_client -connect yourdomain.com:443 2>/dev/null \
  | openssl x509 -noout -text | grep -A3 "Authority Information"
# Look for: CA Issuers - URI:http://... — this is where the intermediate can be fetched

Fixing on Nginx

Your certificate file needs to include both your domain certificate and the intermediate certificate(s), concatenated in order (leaf first, intermediates after):

# Create the full chain file
cat yourdomain.crt intermediate.crt > yourdomain-fullchain.crt

# Or if your CA provides a bundle file
cat yourdomain.crt ca-bundle.crt > yourdomain-fullchain.crt

In your Nginx config:

server {
    listen 443 ssl;
    server_name yourdomain.com;

    # Use the full chain file, not just the domain cert
    ssl_certificate /etc/nginx/ssl/yourdomain-fullchain.crt;
    ssl_certificate_key /etc/nginx/ssl/yourdomain.key;
}

After updating:

nginx -t && systemctl reload nginx

Fixing on Apache

<VirtualHost *:443>
    ServerName yourdomain.com
    SSLEngine on
    SSLCertificateFile /etc/apache2/ssl/yourdomain.crt
    SSLCertificateKeyFile /etc/apache2/ssl/yourdomain.key

    # Apache < 2.4.8: use SSLCertificateChainFile for intermediates
    SSLCertificateChainFile /etc/apache2/ssl/intermediate.crt

    # Apache >= 2.4.8: concatenate into SSLCertificateFile instead
    # SSLCertificateFile /etc/apache2/ssl/yourdomain-fullchain.crt
</VirtualHost>

Fixing on Node.js

const https = require('https');
const fs = require('fs');

const options = {
    key: fs.readFileSync('/etc/ssl/private/yourdomain.key'),
    // cert must include the full chain
    cert: fs.readFileSync('/etc/ssl/certs/yourdomain-fullchain.crt'),
    // Or pass separately:
    // cert: fs.readFileSync('/etc/ssl/certs/yourdomain.crt'),
    // ca: fs.readFileSync('/etc/ssl/certs/intermediate.crt'),
};

https.createServer(options, app).listen(443);

Let's Encrypt and Certbot

Certbot generates a fullchain.pem file that already includes the intermediate. Always use fullchain.pem rather than cert.pem in your web server config:

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

Using cert.pem instead of fullchain.pem is one of the most common sources of incomplete chain errors with Let's Encrypt.


Verify After Fixing

# Confirm the chain is complete
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null \
  | grep -E "Certificate chain|depth|verify"

# Expected output with a complete chain:
# depth=2 ... (root)
# depth=1 ... (intermediate)
# depth=0 CN = yourdomain.com (your cert)
# Verify return code: 0 (ok)

Monitoring SSL Certificate Health

An incomplete chain can emerge after certificate renewal if the renewal process doesn't correctly include intermediates — particularly with manual renewal scripts that copy only the domain certificate. Domain Monitor monitors your SSL certificate health including chain validity, catching incomplete chains before they cause user-facing browser warnings. Create a free account.


Also in This Series

More posts

Wildcard vs SAN vs Single-Domain SSL Certificates: Which Do You Need?

Wildcard, SAN (multi-domain), and single-domain SSL certificates cover different use cases. Here's a clear comparison to help you pick the right type — and avoid paying for coverage you don't need.

Read more
Why DNS Works in One Location but Fails in Another

DNS resolves correctly from your office but fails for users in other countries or on different ISPs. Here's why geographic DNS inconsistency happens and how to diagnose which layer is causing it.

Read more
Registrar Lock vs Transfer Lock: What's the Difference?

Registrar lock and transfer lock are often confused — and disabling the wrong one leaves your domain vulnerable. Here's a clear breakdown of what each does and when to use them.

Read more

Subscribe to our PRO plan.

Looking to monitor your website and domains? Join our platform and start today.