Back to Guides
OpenSSLDebugging

OpenSSL s_client - The Essential SSL/TLS Debugging Tool

s_client is the single most useful command for debugging SSL/TLS issues. It's like curl but shows you everything happening in the TLS handshake.

~10 min readDecember 2025
OpenSSL s_client connection tester visualization

Basic Usage

Connect to a server

openssl s_client -connect example.com:443

This shows: certificate chain, server cert details, TLS version, cipher suite, and session info.

Quick one-liner (most common)

echo | openssl s_client -connect example.com:443 -brief

The echo | sends empty input so the command exits immediately.

Using -brief for clean output

openssl s_client -connect example.com:443 -brief

The -brief flag shows a condensed summary instead of the full handshake details.

Common Use Cases

Check Certificate Expiration

echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

Returns notBefore and notAfter dates for the server certificate.

Testing Different Services

s_client can test any SSL/TLS-enabled service, not just HTTPS. For services that upgrade from plaintext to TLS (STARTTLS), use the -starttls option.

ServiceCommand
HTTPSopenssl s_client -connect example.com:443
SMTP STARTTLSopenssl s_client -connect mail.example.com:587 -starttls smtp
IMAP STARTTLSopenssl s_client -connect mail.example.com:143 -starttls imap
IMAPSopenssl s_client -connect mail.example.com:993
POP3Sopenssl s_client -connect mail.example.com:995
LDAPSopenssl s_client -connect ldap.example.com:636
FTP STARTTLSopenssl s_client -connect ftp.example.com:21 -starttls ftp
MySQL SSLopenssl s_client -connect db.example.com:3306 -starttls mysql
PostgreSQLopenssl s_client -connect db.example.com:5432 -starttls postgres

SNI (Server Name Indication)

openssl s_client -connect 192.168.1.1:443 -servername www.example.com

Why SNI matters: When multiple virtual hosts share the same IP address, the server needs to know which hostname you're connecting to before it can send the correct certificate. Without -servername, you might get the wrong certificate (often the server's default cert).

Common SNI scenarios

  • CDNs hosting multiple sites on shared IPs
  • Cloud load balancers with multiple backend apps
  • Reverse proxies with multiple domains
  • Testing certificates before DNS changes
# Test against IP before DNS cutover
openssl s_client -connect 203.0.113.50:443 -servername newsite.example.com

Troubleshooting Connection Issues

Connection Refused

connect: Connection refused

Causes:

  • Service isn't running on that port
  • Firewall blocking the connection
  • Wrong port number

Connection Timed Out

connect: Connection timed out

Causes:

  • Network routing issues
  • Host unreachable
  • Firewall dropping packets silently

Certificate Verify Failed

verify error:num=20:unable to get local issuer certificate

Causes:

  • Missing CA bundle on your system
  • Self-signed certificate
  • Server not sending intermediate certificates

Fix: Specify a CA bundle:

openssl s_client -connect example.com:443 -CAfile /etc/ssl/certs/ca-certificates.crt

Handshake Failure

SSL routines:ssl3_read_bytes:tlsv1 alert handshake failure

Causes:

  • No shared cipher suites
  • TLS version mismatch
  • Client certificate required but not provided

Debug: Try specific TLS versions to isolate:

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

Verify Return Codes Reference

When s_client connects, it shows Verify return code at the end. Here's what the codes mean:

CodeMeaningCommon Fix
0OKCertificate valid ✓
2Unable to get issuer certificateMissing intermediate cert
10Certificate has expiredRenew certificate
18Self-signed certificateExpected for internal certs
19Self-signed cert in chainRoot CA not trusted
20Unable to get local issuerCA not in trust store
21Unable to verify first certificateServer missing intermediate
62Hostname mismatchWrong cert for domain

Using Custom CA Bundle

For internal CAs or when testing against non-public certificates, you need to tell OpenSSL where to find your trusted CAs.

Specify a CA file

openssl s_client -connect example.com:443 -CAfile /path/to/ca-bundle.crt

Specify a CA directory

openssl s_client -connect example.com:443 -CApath /etc/ssl/certs/

Use case: Testing against internal PKI infrastructure, corporate CAs, or development environments with custom root certificates.

Quick Reference Card

Common Tasks Cheat Sheet

TaskCommand
Basic testopenssl s_client -connect host:443
Quick test (auto-exit)echo | openssl s_client -connect host:443 -brief
Check expirationecho | openssl s_client -connect host:443 2>/dev/null | openssl x509 -noout -dates
Download certecho | openssl s_client -connect host:443 2>/dev/null | openssl x509 -out cert.pem
Show chainopenssl s_client -connect host:443 -showcerts
Test TLS 1.3openssl s_client -connect host:443 -tls1_3
SMTP STARTTLSopenssl s_client -connect host:587 -starttls smtp
With SNIopenssl s_client -connect host:443 -servername hostname

All Options

OptionDescription
-connect host:portConnect to specified host and port
-servername nameSet SNI hostname
-showcertsShow full certificate chain
-briefMinimal output
-tls1_2 / -tls1_3Force specific TLS version
-cipher CIPHERUse specific cipher suite
-starttls protoSTARTTLS for smtp, imap, ftp, etc.
-CAfile fileSpecify trusted CA bundle
-cert fileClient certificate for mTLS
-key fileClient private key for mTLS

Frequently Asked Questions

Why does s_client hang after connecting?

It's waiting for input. Press Ctrl+C to exit, or use echo | before the command to auto-close.

What does "Verify return code: 21" mean?

The server didn't send its intermediate certificate. The server admin needs to fix their certificate chain by including the intermediate CA certificate.

How do I test if a server supports TLS 1.3?

Run openssl s_client -connect host:443 -tls1_3. If it connects successfully, TLS 1.3 is supported. If you get a handshake error, the server doesn't support it.

Why do I get a different certificate than my browser shows?

You may need to specify SNI with -servername hostname. Without it, you get the server's default certificate, which may differ from the one served to browsers that send SNI.

Related Resources