esc
Security Security

SSL Certificate Chain Explained: Root, Intermediate and Leaf Certificates

By helpers.work Updated 10 min read
SSL certificate chain for example.com, with the leaf certificate signed by an intermediate CA and the intermediate signed by a trusted root CA in the browser trust store

An SSL certificate chain (more precisely, a TLS certificate chain) is the list of certificates that links your site's certificate to a root certificate the client already trusts. Your leaf certificate is signed by an intermediate certificate, and the intermediate is signed by the root. The client checks each signature in turn. If any link is missing or invalid, the connection fails with an "untrusted certificate" error.

The most common chain problem is simple: the server sends its own certificate but not the intermediate. Browsers often hide this, while curl, APIs and mobile apps fail with errors such as unable to get local issuer certificate. The fix is to install the full chain on the server.

ISRG Root X1                    root: in the client's trust store, not sent
  └─ signs  R11                 intermediate: sent by your server
       └─ signs  example.com    leaf: your certificate, sent by your server
Certificate Also called Who has it Typical lifetime Sent by your server
Leaf End-entity, server certificate You 90 to 200 days Yes
Intermediate Subordinate or issuing CA The certificate authority (CA) A few years Yes
Root Trust anchor Browsers and operating systems 15 to 25 years No

The leaf certificate

The leaf is the certificate issued for your domain. It contains your hostnames in the Subject Alternative Name (SAN) list, your public key, the validity period, and the name of the CA that signed it in the Issuer field.

Leaf certificates are getting shorter-lived. Under CA/Browser Forum rules, public TLS certificates issued from March 2026 may be valid for at most 200 days, falling to 100 days in 2027 and 47 days in 2029. Automated renewal is no longer optional.

Intermediate certificates

CAs almost never sign leaf certificates with their root key. The root signs one or more intermediate certificates, and those sign your leaf. This keeps the valuable root key offline, and lets the CA replace or revoke an intermediate without touching the root. CAs rotate intermediates regularly, so the intermediate that signs your next certificate may be different from the one you have today.

The root certificate

The root signs itself. It is trusted because it ships in a trust store: the Mozilla root store (used by Firefox and many Linux distributions), the Apple, Microsoft and Android stores, and the Chrome Root Store. A chain is only valid if it ends at a root in the store of the client that is connecting.

How a client validates the chain

During the TLS handshake, the server sends its leaf certificate and the intermediates. The client then:

  1. Builds a path from the leaf to a trusted root by matching each certificate's Issuer to the Subject of the next one (and the Authority Key Identifier to the Subject Key Identifier).
  2. Verifies each signature with the public key of the certificate above it.
  3. Checks validity dates for every certificate in the path, not only the leaf.
  4. Checks the hostname against the leaf's SAN entries.
  5. Checks constraints and usage, for example that the intermediate is allowed to act as a CA.
  6. Optionally checks revocation, using CRLs or OCSP.

If every step passes, the connection is trusted.

The most common failure: a missing intermediate

A server that sends only the leaf certificate forces the client to find the intermediate on its own. Clients behave very differently here:

Client Missing intermediate
Chrome, Edge, Safari Usually works: fetches it from the leaf's AIA URL or uses a cached copy
Firefox Usually works: ships a preloaded list of known intermediates
curl, wget, OpenSSL Fails
Python, Node.js, Go, Java, .NET HTTP clients Fails (by default)
Many Android and iOS apps, IoT devices Often fails
Webhooks and API integrations Usually fails

That is why the site "works for me" in a browser while monitoring, payment webhooks or a mobile app break. The AIA (Authority Information Access) extension in the leaf contains a URL where the intermediate can be downloaded, but only some clients use it.

Error messages that mean a broken chain

Client Error
curl curl: (60) SSL certificate problem: unable to get local issuer certificate
OpenSSL verify error:num=20:unable to get local issuer certificate and num=21:unable to verify the first certificate
Python [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate
Node.js UNABLE_TO_VERIFY_LEAF_SIGNATURE (unable to verify the first certificate)
Java PKIX path building failed ... unable to find valid certification path to requested target
Go x509: certificate signed by unknown authority
Chrome NET::ERR_CERT_AUTHORITY_INVALID

The same messages also appear when a certificate comes from a private CA that the client does not trust, so check the chain before you change the client.

How to check a certificate chain

With a web tool: the SSL Certificate Checker connects to your host, shows every certificate the server presents with its issuer and expiry date, and tells you whether the chain reaches a trusted root. Unlike a browser, it does not quietly fill in a missing intermediate.

With OpenSSL:

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

Look at the Certificate chain section at the top of the output:

Certificate chain
 0 s:CN = example.com
   i:C = US, O = Let's Encrypt, CN = R11
 1 s:C = US, O = Let's Encrypt, CN = R11
   i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
---
Verify return code: 0 (ok)
  • s: is the subject and i: is the issuer. Each certificate's i: should match the next certificate's s:.
  • Certificate 0 must be your leaf.
  • If only certificate 0 is listed and the result is Verify return code: 21 (unable to verify the first certificate), the intermediate is missing.

Always pass -servername. Without it, a server that hosts several sites may return a different, default certificate. To check a certificate file before deploying it:

openssl verify -untrusted chain.pem cert.pem

How to fix a missing intermediate

Configure the server with a file that contains your leaf certificate first, followed by the intermediates. Most CAs provide this as a "bundle", "chain" or "full chain" file.

Nginx:

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

With Certbot, fullchain.pem contains the leaf and the intermediate, while cert.pem contains only the leaf. Pointing ssl_certificate at cert.pem is the classic cause of a broken chain.

Apache 2.4.8 and later:

SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

SSLCertificateChainFile is deprecated since Apache 2.4.8. Put the chain in SSLCertificateFile instead.

Building a chain file by hand: if your CA sends separate files, concatenate them in order, leaf first:

cat example_com.crt intermediate.crt > fullchain.pem

Load balancers and CDNs: managed certificates include the chain automatically. When you upload your own certificate, for example to AWS Certificate Manager, paste the intermediates into the separate certificate chain field.

Reload the server and check again with the SSL Checker or openssl s_client.

Other chain problems

Expired intermediate or root

Every certificate in the path has its own expiry date. An intermediate or cross-signed root can expire while your leaf is still valid. The best-known case was on 30 September 2021, when the old DST Root CA X3 that cross-signed Let's Encrypt expired. Up-to-date clients built a path to ISRG Root X1 instead, but older clients with outdated trust stores or OpenSSL 1.0.x failed. The fix on the client side is to update the CA bundle or the operating system.

Wrong order

TLS 1.2 requires the leaf first, then each issuer in order. TLS 1.3 only requires the leaf to come first, and most modern clients tolerate any order, but some older or embedded clients do not. Keep the standard order: leaf, then intermediates, then nothing else.

Sending the root or unrelated certificates

Including the root is unnecessary: clients ignore it and it adds bytes to every handshake. Including an old or unrelated intermediate can confuse strict clients. Send exactly the leaf and the intermediates that link it to the root.

Self-signed or private CA certificates

Internal services often use a private CA. Clients reject these chains with errors such as self signed certificate in certificate chain unless the private root is added to their trust store. Add it explicitly, for example with NODE_EXTRA_CA_CERTS in Node.js, REQUESTS_CA_BUNDLE in Python requests, or --cacert in curl.

Do not "fix" chain errors by disabling verification with curl -k, verify=False or rejectUnauthorized: false. That removes protection against man-in-the-middle attacks instead of fixing the chain.

Hostname mismatch

A perfectly chained certificate still fails if the hostname is not in its SAN list. Chrome reports NET::ERR_CERT_COMMON_NAME_INVALID, and curl reports no alternative certificate subject name matches target host name. This is not a chain problem: reissue the certificate with the correct names, or check whether DNS points to the wrong server with the DNS Lookup. After a migration, the guide to DNS propagation explains why some users can still reach the old host.

Summary

A certificate chain links your leaf certificate through one or more intermediates to a root the client already trusts. Your server must send the leaf and the intermediates, in order, and nothing else. When a site works in Chrome but fails in curl, Java, Python or a mobile app, a missing intermediate is almost always the cause, and the fix is to install the full chain file.

Check any host with the SSL Certificate Checker, which shows every certificate in the chain with its issuer and expiry date.

FAQ

Frequently asked questions

What is an SSL certificate chain?

It is the ordered list of certificates that links your site's certificate to a trusted root. The leaf certificate is signed by an intermediate certificate, the intermediate is signed by a root, and the root is stored in the client's trust store. The client checks every signature up the chain.

Why does my certificate work in Chrome but fail in curl or an app?

The server is almost certainly not sending the intermediate certificate. Chrome, Edge and Safari can fetch or cache missing intermediates, and Firefox ships a list of them, which hides the problem. curl, OpenSSL, Java, Python, Node.js and many mobile apps do not, so they fail. Install the full chain on the server.

What does "unable to get local issuer certificate" mean?

The client could not find the certificate that issued the one it is checking. Usually the server is missing an intermediate certificate. Less often, the client's CA bundle is outdated or the certificate comes from a private CA the client does not trust.

Should the server send the root certificate?

No. The client must already have the root in its trust store, so sending it only adds bytes to every handshake. The server should send the leaf certificate followed by the intermediate certificates.

What is fullchain.pem?

With Let's Encrypt and Certbot, fullchain.pem contains your leaf certificate followed by the intermediate certificate. Point your web server at fullchain.pem, not cert.pem, which contains only the leaf.

How do I check my certificate chain?

Use an SSL checker, or run openssl s_client -connect example.com:443 -servername example.com -showcerts. Both show every certificate the server sends and whether the chain reaches a trusted root.

Try it yourself

Related tools

All tools

More guides in the helpers.work blog

Practical, no-nonsense guides on DNS, email, networking and security — plus 68 free tools to go with them.

Read the blog Browse all tools