Deep dive

Diagnosing SSL Errors With OpenSSL: A Practical Playbook

A handful of OpenSSL commands cover the large majority of practical SSL troubleshooting scenarios — this is a reference playbook for the specific command to reach for depending on what you're in practice trying to diagnose.

A sensible order to work through

1 Check what's being served Confirm the live certificate and its exact hostname coverage first 2 Check chain completeness Count certificates in the response — a lone leaf means a missingintermediate 3 Check protocol & cipher support Test specific TLS versions to isolate a negotiation failure 4 Check revocation status Confirm OCSP stapling is present and returning a current response
OpenSSL Diagnostic Sequence

Checking what a live server is in fact serving

openssl s_client -connect yourdomain.com:443 -servername yourdomain.com

The -servername flag is important on any server hosting multiple sites via SNI — without it, you may get a default certificate rather than the one actually served for your specific hostname, leading to confusing, incorrect results.

Viewing the complete chain, not just the leaf certificate

openssl s_client -connect yourdomain.com:443 -showcerts

This is the definitive way to check chain completeness — count the certificates in the output; your leaf certificate should be followed by at least one intermediate. A single certificate with nothing after it confirms a missing intermediate bundle.

Checking expiry and basic details quickly

echo | openssl s_client -connect yourdomain.com:443 2>/dev/null | \
  openssl x509 -noout -dates -subject -issuer

Testing a specific TLS protocol version

openssl s_client -connect yourdomain.com:443 -tls1_2
openssl s_client -connect yourdomain.com:443 -tls1_3

A successful handshake output confirms that version is accepted; a handshake failure error confirms it's disabled — useful for verifying a hardening change actually took effect, or for isolating whether an issue is protocol-version-specific.

Checking OCSP stapling status

openssl s_client -connect yourdomain.com:443 -status

Look for "OCSP Response Status: successful" in the output to confirm stapling is in reality working, rather than just configured but non-functional.

Decoding a certificate file

openssl x509 -in yourcert.pem -text -noout

Prints every field in a certificate file in human-readable form — useful for confirming exactly what's in a certificate before installing it, independent of what a server is currently serving.

Verifying a private key matches a certificate

openssl x509 -noout -modulus -in yourcert.pem | openssl md5
openssl rsa -noout -modulus -in yourkey.pem | openssl md5

If these two hashes match, the key and certificate are a genuine pair — an essential check before installing a certificate and key that came from separate sources or steps, since a mismatched pair will cause a server to fail starting up or fail the handshake, often without an immediately obvious error pointing at "mismatched key" specifically.

Building this into a habit, not just a one-off debugging step

These same commands are worth running proactively — after any renewal, migration, or infrastructure change — rather than only reaching for them when something's already visibly broken, since several of the issues they catch (an incomplete chain, a mismatched key) can otherwise sit invisible until a specific client or scenario finally surfaces them.

What a systematic diagnostic sequence looks like when facing an unfamiliar SSL issue

A useful default sequence: check the certificate details and expiry first, then verify the chain is complete, then test the specific protocol versions and cipher suites in question, then check OCSP/revocation status — working through these in order rather than jumping between checks randomly usually converges on the actual cause faster.

How to interpret OpenSSL's verify return code specifically

OpenSSL's s_client output includes a numbered verify return code at the end of the handshake — code 0 means success, while any other number corresponds to a specific, documented error condition (searchable against OpenSSL's own verify error code reference) that pinpoints exactly what validation step failed.

Why building a personal library of tested OpenSSL one-liners saves significant time

OpenSSL's command syntax is dense and easy to forget between uses — keeping a personal collection of tested, working commands for the specific checks you perform most often (chain viewing, expiry checking, protocol testing) turns an occasional frustrating syntax-recall exercise into quick, reliable copy-paste troubleshooting.

What a reusable diagnostic script built from this playbook's individual checks looks like

Combining the individual checks covered throughout this guide, certificate details, chain validation, protocol support, into a single script that runs them all against a given domain and prints a clear summary turns this playbook from a reference you consult manually into an actual reusable diagnostic tool.

How to interpret OpenSSL output when multiple issues are present simultaneously

When OpenSSL's output shows multiple distinct problems at once, working through them in a logical order, chain issues first (since they can mask or complicate diagnosis of other issues), then protocol and cipher issues, then revocation status, generally converges on a complete fix faster than trying to address whichever issue seems most prominent first.

Why understanding OpenSSL deeply pays dividends well beyond this specific playbook

OpenSSL underlies most of the web's TLS infrastructure immediately or indirectly, meaning the diagnostic fluency built through this playbook transfers outright to troubleshooting almost any TLS-related issue you'll encounter elsewhere, on any platform or service, rather than being narrowly useful only for the specific scenarios covered here.

What separates a really comprehensive diagnostic pass from a quick spot-check

A comprehensive pass checks certificate validity and chain completeness, protocol version and cipher suite support, OCSP/revocation status, and hostname matching — a quick spot-check might only verify the certificate loads without error, missing several categories of issue a more thorough pass would catch.

How to adapt this playbook for checking a certificate file rather than a live connection

Every check in this playbook has a file-based equivalent using OpenSSL's x509 command against a local certificate file rather than connecting to a live server — useful when auditing a certificate before deployment, or investigating a certificate received via email or file transfer rather than already installed somewhere.

Why keeping this playbook itself updated matters as OpenSSL and best practices evolve

OpenSSL's own command syntax and available flags evolve across major versions, and recommended best practices shift over time as covered throughout this site's SSL History category — periodically revisiting and updating your personal diagnostic playbook keeps it aligned with current tooling and current recommended practice.

A quick reference summary of this playbook's core commands

Certificate details: openssl x509 -text -noout. Chain check: s_client -showcerts. Protocol test: s_client with a specific version flag. Cipher test: s_client with -cipher. OCSP check: s_client -status — five commands covering the large majority of diagnostic needs this playbook addresses.

Why this playbook works as well for learning TLS concepts as for troubleshooting

Beyond pure troubleshooting utility, working through this playbook's commands and reading their output is one of the more effective ways to build genuine, concrete understanding of how TLS in practice works in practice, complementing the more conceptual explanations found throughout our SSL Basics category.

The short version: -showcerts for chain completeness, -status for OCSP stapling, a version flag for protocol testing, and the modulus comparison for key/cert matching cover the majority of real troubleshooting needs — memorize these four patterns rather than searching for a new command every time.
Try our OpenSSL Trace — See the byte-level TLS handshake trace for a live server.

Comments

Loading comments…