Check the chain by inspecting what the server actually sends and running a fail-fast verification: openssl s_client -connect example.com:443 -servername example.com -showcerts -verify_return_error, then confirm offline bundles with openssl verify -CAfile roots.pem -untrusted intermediates.pem leaf.pem. Success means the server transmits the leaf plus required intermediates and verification returns no errors. Anything less means a client somewhere will reject the connection.
TL;DR:
- Most server-sent certificate chains are incomplete, with missing intermediates causing verification failures on clients other than browsers.
- Using the fail-fast verification flag in OpenSSL and checking the verification code helps confirm if the chain is fully valid, not just if the certificates are present.
- Local bundle verification should match the server's sent chain, ensuring correct file order and trust store management before deployment.
- Browsers often fetch missing intermediates automatically, making SSL issues less visible in them but causing failures in curl, mobile apps, or webhook integrations.
- Regular, automated checks of live endpoints and local files, along with proactive expiry alerts, significantly reduce the risk of chain-related outages.
Table of Contents
- What an SSL chain check actually tells you
- Live endpoint checks with OpenSSL: exact commands and output
- Verifying local PEM files before you deploy
- Why a site works in your browser but fails in curl or mobile apps
- Common chain problems and how admins actually fix them
- A repeatable verification workflow worth adopting
- What years of chain failures actually teach you
- Get a fast, free read on your certificate chain
- Where to read more on the commands and behavior covered here
- Sources
- FAQ
What an SSL chain check actually tells you
A certificate chain has three parts: the leaf certificate for your domain, one or more intermediates, and a root that clients already trust. Servers should never send the root itself since clients supply it from their own trust store, as explained by MDN's certificate authority glossary. When you run a chain check, you're really reading several distinct signals at once.
- Subject Alternative Names (SANs): confirm the hostname you're connecting to is actually covered.
- Validity window: not-before and not-after dates, since an expired leaf breaks everything downstream.
- Signature algorithm and key type: mismatches here can trigger silent rejections in stricter clients.
- Negotiated protocol and cipher: shown separately from the chain but relevant to overall transport security.
There's a difference between what the server sends (visible with -showcerts) and what a client actually verifies against its trust store. OpenSSL's s_client continues past verification errors by default, so a clean-looking certificate list is not proof of a working chain, according to OpenSSL's own documentation. You need the fail-fast flag to know for sure.
Live endpoint checks with OpenSSL: exact commands and output
Run this against any public HTTPS endpoint:
printf ' ' | openssl s_client -connect example.com:443 -servername example.com -showcerts -verify_return_error- Read the certificate list between
Certificate chainand---: each entry should show subject and issuer lines, and you want to see the leaf followed by one or more intermediates. - Check the final verification line:
Verify return code: 0 (ok)means the chain validated; anything else names the specific failure.
The -servername flag sends SNI, which matters on shared hosting where one IP serves multiple certificates. -showcerts prints every certificate the server transmitted, not just the leaf. -verify_return_error is the flag that turns this from a passive dump into an actual pass/fail test, because without it s_client will report certificate details even when verification technically failed.
A complete chain shows two or three certificates in the list and a clean return code. A missing intermediate typically shows only the leaf certificate, with a return code like unable to get local issuer certificate. That single error message is the most common signal of an incomplete server-side bundle.
Pro Tip: Run this check from a fresh shell, a container, or a CI agent rather than your everyday workstation. Some systems cache intermediates fetched via AIA, which can mask a genuinely broken chain on the server side.

Verifying local PEM files before you deploy
Before a certificate ever touches a production server, test the bundle files directly. This catches problems that live-endpoint testing can't, because you're checking the raw materials rather than what's already been uploaded somewhere.
Run openssl verify -show_chain -CAfile roots.pem -untrusted intermediates.pem leaf.pem to validate the leaf against your intermediates and a trust store. The -show_chain flag prints the exact path OpenSSL constructed, which is useful when a certificate could be verified more than one way. OpenSSL's verify documentation separates inputs into the target certificate, untrusted helper certificates, and a trusted root store, and that separation is exactly why the same chain can pass on one machine and fail on another with a different trust store.
A few practical points to keep straight:
-untrustedsupplies intermediates that help build the path but are not themselves trusted.-CAfileshould point to a genuine root bundle, not a copy of your own intermediates.- A successful run prints the constructed path along with
OK; failures name the exact break, such as an expired certificate or an unknown issuer. - For Nginx and most modern servers,
ssl_certificateshould point atfullchain.pem, notcert.pem, per Let's Encrypt's own community guidance, sincecert.pemcontains only the leaf.
Why a site works in your browser but fails in curl or mobile apps
This is one of the more confusing failure modes, and it comes down to one behavior: desktop browsers often fetch missing intermediates automatically using the Authority Information Access (AIA) extension. Curl, many mobile app networking stacks, server-side HTTP libraries, and webhook senders typically do not attempt this fetch, so an incomplete server-sent chain can look perfectly fine in a browser while breaking everywhere else.
The fix is diagnostic before it's technical:
- Run the same
openssl s_client -showcertscommand described earlier and count the certificates in the list. - Test the same URL with curl and compare the result against the browser experience.
- Reproduce the failure from a device or network you don't normally use, since some environments carry cached intermediates.
The operational cost of skipping this step shows up as webhook deliveries that silently fail, mobile app users who can't log in, and API integrations that throw obscure TLS errors while your own dashboard reports everything as healthy.
Pro Tip: If a partner or customer reports a broken connection you can't reproduce in a browser, ask them to run a curl test or check with an external SSL tool before assuming the problem is on their end.
Common chain problems and how admins actually fix them
Most chain failures trace back to one of a small number of causes, and the fix is usually straightforward once you've identified which one you're dealing with.
- Missing intermediate: the server sends only the leaf. Download the correct intermediate bundle from your certificate authority, as Ssl walks through, and concatenate it with the leaf.
- Wrong file order: certificates must be ordered leaf first, then intermediates, with the root never included at all.
- Server misconfiguration: Nginx needs
ssl_certificatepointed at the full bundle; Apache uses separateSSLCertificateFileandSSLCertificateChainFiledirectives depending on version, so check which your setup expects. - Renewal automation gotchas: some ACME clients overwrite the leaf without refreshing the intermediate bundle, especially after a CA rotates its intermediate certificates.
- After any renewal, rerun both the live
s_clientcheck and a localverifypass rather than assuming the automation worked. - Stale client trust stores: if a specific device or older client still fails after your server checks out clean, the fix may sit entirely on that client's end, outside your control.
A repeatable verification workflow worth adopting
The teams that avoid chain-related outages tend to run the same short routine every time, rather than treating SSL as something you check once and forget.
- Pre-deploy: run
openssl verifyagainst your bundle files locally to confirm composition before anything goes live. - Post-deploy: run the live
s_clientcheck, then confirm with an external SSL checker and a manual test from a second client like curl. - Ongoing monitoring: schedule expiry alerts well ahead of renewal dates, since automated monitoring is one of the most common operational guards against chain-related outages after a certificate is correctly installed.
- Complementary control: Certificate Transparency monitoring catches unexpected certificate issuance for your domain, which chain validation alone doesn't cover.
Folding these steps into your deployment pipeline, rather than running them manually after something breaks, turns SSL verification into a five-minute habit instead of an incident response.
What years of chain failures actually teach you

The pattern repeats often enough to be predictable: an automation script swaps a renewed leaf certificate onto a server without touching the intermediate bundle, or someone uploads a certificate to a CDN's dashboard in the wrong field order, and the chain quietly breaks for a subset of clients while the dashboard shows green. Stale intermediates left over from a CA's older certificate hierarchy are another repeat offender, particularly on infrastructure that hasn't been touched in a year or two.
The heuristic that saves the most time: check what the server actually sends before you check anything else, then verify with a client you don't normally use. Automation that renews certificates should also assert the verification result, not just confirm the file was written. When you want a fast second opinion from outside your own network, an external tool removes the guesswork about what your own machine might be caching.
— Andreas
Get a fast, free read on your certificate chain
Running OpenSSL commands from a terminal is the most direct way to check a chain, but a quick external confirmation catches problems your own network might hide, like a cached intermediate or a trust store that's more forgiving than your visitors' devices. The SSL Checker does a live handshake against your domain and reports chain completeness, expiry, SANs, and the negotiated cipher in one pass, with no installation or account required.

Pair it with the Response Headers Inspector to check security headers like HSTS alongside your certificate setup, since transport security and header configuration tend to get reviewed together. For the renewal problem specifically, set up the Website Uptime Monitor to get alerted before an expiring certificate turns into a client-facing outage rather than finding out from a support ticket.
Run a check now at Pingfloat and see exactly what your server is sending.
Where to read more on the commands and behavior covered here
- OpenSSL's s_client documentation covers every flag referenced above, including how verification errors are handled by default.
- The OpenSSL verify command reference details
-CAfile,-untrusted, and-show_chainbehavior for local bundle testing. - Let's Encrypt's community explanation of
fullchain.pemversuscert.pemis worth reading before touching Nginx config. - Ssl walks through sourcing and applying the correct bundle from a CA.
Sources
- openssl-s_client - OpenSSL 3.4 documentation
- verify - OpenSSL 1.0.2 documentation
- Difference between fullchain.pem and cert.pem - Let's Encrypt community
- Ssl
FAQ
How do I read an OpenSSL certificate chain?
Run openssl s_client -connect host:443 -servername host -showcerts and read the numbered certificate blocks from top to bottom, where the first is your leaf and each subsequent one is an intermediate. The subject and issuer lines on each certificate show you how they link together, and the final verify return code tells you whether the chain actually validated.
Why is SSL not used anymore?
The term "SSL" is largely used out of habit; modern connections run on TLS, which succeeded SSL after SSL's later versions were found to have serious weaknesses. Most tools and documentation, including OpenSSL's own command names, still use "SSL" informally even though the protocol in use today is TLS.
Is port 443 TLS or SSL?
Port 443 is the standard port for HTTPS traffic, and in practice nearly all of that traffic today is TLS rather than legacy SSL. The port itself doesn't dictate the protocol version, which is negotiated during the handshake between client and server.
How do I check the SSL status of a website?
Run a live handshake test with openssl s_client -connect domain:443 -servername domain -showcerts -verify_return_error to see the certificates sent and whether verification passes. A tool like Pingfloat's SSL Checker gives the same information, including expiry and SANs, without needing a terminal.
