Diagnose TLS endpoints with openssl s_client
You will use openssl s_client to inspect a TLS endpoint, check its certificate name, see the certificates it sends, and test a protocol that upgrades an existing connection with STARTTLS. These are diagnostic connections, not a replacement for the TLS settings in an application.
The route
Jump straight to the step you need, or tick off Done means at the end.
Time: about 10 minutes for a straightforward check. You need a shell, the OpenSSL package, and network access to the service you are testing. The examples below use example.com; replace it with a host you are authorised to test.
Checkpoint 1: confirm the local tool
- Check the installed version and the options this guide uses.
openssl version
openssl s_client -help 2>&1 | grep -E -- '-brief|-verify_hostname|-starttls|-showcerts|-verify_return_error'
On the machine used for this guide, the program reports OpenSSL 3.6.1, released on 27 January 2026. The installed manual is dated 18 August 2026 and identifies the command as OpenSSL 3.0.13 documentation, so option details should be checked against the binary when moving between distributions.
Checkpoint 2: make a normal HTTPS handshake
- Connect to the service with SNI and request a compact result.
openssl s_client \
-brief \
-connect example.com:443 \
-servername example.com </dev/null
-connect selects the destination. -servername puts the DNS name in the TLS Server Name Indication extension, which is essential when several sites share one address. OpenSSL 1.1.1 and later normally derive SNI from a DNS-style name in -connect, but writing it explicitly makes the test clear and avoids surprises when you use an address, proxy or unusual target.
-brief keeps the result readable. A successful run includes lines similar to these, although the address, protocol, cipher and certificate change over time:
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=example.com
Verification: OK
DONE
If you omit input redirection, the command remains interactive after the handshake. It displays received data and sends typed lines to the server. Use Q on a line by itself to exit, or use </dev/null for a one-shot inspection.
Checkpoint 3: make certificate failure fail the command
- Run the handshake with an explicit hostname check and stop on verification errors.
openssl s_client \
-brief \
-connect example.com:443 \
-servername example.com \
-verify_hostname example.com \
-verify_return_error </dev/null
This distinction matters. s_client is a test tool and, by default, continues after certificate verification errors so it can show diagnostic information. A connection that prints a verification error is therefore not automatically a failed process or an unsafe server. -verify_return_error changes that behaviour and normally aborts the handshake when verification fails. -verify_hostname supplies the expected peer name for hostname verification.
Do not turn a passing s_client probe into a claim that every client is safe. Applications can use different trust stores, hostname rules, protocol limits or certificate policies. This command tests the choices you give it.
Inspect the certificate chain and negotiated protocol
- Request the server's sent certificate list when the compact output is not enough.
openssl s_client \
-connect example.com:443 \
-servername example.com \
-showcerts \
-prexit </dev/null
-showcerts prints the certificates the server sent, in the order it sent them. It is not a verified chain: use the verification result separately. -prexit prints session information when the program exits, including cases where a later request caused a problem. This is useful when a service asks for a client certificate only after a connection is established.
To test a protocol boundary, force a specific version and compare the result:
openssl s_client -brief -tls1_2 -connect example.com:443 -servername example.com </dev/null
openssl s_client -brief -tls1_3 -connect example.com:443 -servername example.com </dev/null
A failed forced-version test means that version was not negotiated with that endpoint under the local OpenSSL policy. It does not by itself identify whether the server, a proxy or local policy caused the failure.
Test STARTTLS services
- Tell
s_clientwhich clear-text protocol must upgrade before TLS.
openssl s_client \
-brief \
-starttls smtp \
-connect smtp.example.com:587 \
-servername smtp.example.com \
-name mail.example.com \
-verify_return_error </dev/null
-starttls supports protocol keywords including smtp, pop3, imap, ftp, xmpp, postgres, mysql, ldap and others listed by the local manual. For SMTP and LMTP, -name controls the name used in the EHLO or LHLO message. It is separate from TLS SNI. Use the name the service expects, not a made-up value.
Common traps and safe boundaries
- Wrong virtual host: connecting by IP can select a default certificate. Add
-servernamewith the intended DNS name. - False success: without
-verify_return_error, verification errors are displayed while the handshake may continue. - Incomplete diagnosis:
-showcertsshows what was sent, not whether the chain is trusted. - Secret exposure: never use
-keylogfileon a shared system unless you deliberately need packet decryption. It writes TLS secrets that can decrypt captured traffic. - Client credentials:
-certis only used when the server requests a client certificate. Keep private key files protected and do not paste their contents into a terminal transcript. - Network impact: these commands make real connections and may send protocol greetings or HTTP requests. Do not probe systems without permission. No elevated privileges are needed for the examples.
Done means
- You confirmed which OpenSSL binary and version is installed.
- You recorded the negotiated protocol, cipher and peer certificate for the intended SNI name.
- You repeated the check with hostname verification and
-verify_return_error. - You used
-showcertswhen the server's sent chain needed inspection. - You selected the correct
-starttlsprotocol and separated its application name from TLS SNI.