Start with openssl s_client -connect enterno.io:443 -servername enterno.io -verify_hostname enterno.io -verify_return_error -brief -no-interactive. SNI selects the server certificate; hostname verification and strict error handling tell you whether that certificate is acceptable for the name you meant to reach.

This is a tested set of 30 commands, with observed output and process status from 13 November 2026. Use the route below to narrow down a failed handshake. Certificate and server settings are live, so re-run the relevant probe before acting on an old result.
What you need
You need OpenSSL, access to the target TCP port, and the DNS name the client expects. These probes ran with OpenSSL 3.5.8. If an older build rejects -no-interactive, omit that option and close standard input with </dev/null.
Step 1. Establish certificate trust and hostname identity
A successful TCP and TLS exchange is not a hostname check. OpenSSL documents that s_client normally continues after verification errors so you can inspect them. Add -verify_return_error to fail on a verification error, and -verify_hostname to check the intended DNS name. -servername only supplies SNI to select the virtual host.
$ openssl s_client -connect enterno.io:443 -servername enterno.io -verify_hostname wrong.example -verify_return_error -no-interactive
Verification error: hostname mismatch
Verify return code: 62 (hostname mismatch)
# exit 1
| № | Purpose | Command | Observed output | exit |
|---|---|---|---|---|
| 1 | Inspect the full handshake | openssl s_client -connect enterno.io:443 -servername enterno.io -no-interactive | Verify return code: 0 (ok) | 0 |
| 2 | Get a compact handshake summary | openssl s_client -connect enterno.io:443 -servername enterno.io -brief -no-interactive | Protocol version: TLSv1.3 | 0 |
| 3 | See the chain sent by the server | openssl s_client -connect enterno.io:443 -servername enterno.io -showcerts -no-interactive | Certificate chain | 0 |
| 4 | Stop on a chain error | openssl s_client -connect enterno.io:443 -servername enterno.io -verify_return_error -no-interactive | Verify return code: 0 (ok) | 0 |
| 5 | Check the intended hostname | openssl s_client -connect enterno.io:443 -servername enterno.io -verify_hostname enterno.io -verify_return_error -no-interactive | Verify return code: 0 (ok) | 0 |
| 6 | Detect a hostname mismatch | openssl s_client -connect enterno.io:443 -servername enterno.io -verify_hostname wrong.example -verify_return_error -no-interactive | Verification error: hostname mismatch | 1 |
| 7 | Compact strict check | openssl s_client -connect enterno.io:443 -servername enterno.io -brief -verify_return_error -no-interactive | Protocol version: TLSv1.3 | 0 |
| 8 | Request stapled OCSP | openssl s_client -connect enterno.io:443 -servername enterno.io -status -no-interactive | OCSP response: no response sent | 0 |
-showcerts lists certificates the server sent; it does not by itself prove that your trust store accepts the path. In this run -status printed OCSP response: no response sent. That tells us no stapled response arrived in this handshake, not whether the certificate was revoked. If you need dates, extract the leaf certificate from the chain and inspect it with openssl x509 -noout -dates.
For the next layer of diagnosis, see the certificate check guide, certificate types, and TLS handshake walkthrough.
Step 2. Isolate protocol and application negotiation
Force TLS 1.2 and TLS 1.3 separately when investigating client compatibility. Both worked in this sample. The TLS 1.1 probe stopped locally with no protocols available, so it says nothing conclusive about what the server accepts. Its trailing Verify return code: 0 (ok) is not evidence of a successful handshake.
$ openssl s_client -connect enterno.io:443 -servername enterno.io -tls1_1 -no-interactive
error:0A0000BF:SSL routines:tls_setup_handshake:no protocols available
# exit 1
| № | Purpose | Command | Observed output | exit |
|---|---|---|---|---|
| 9 | Force TLS 1.2 | openssl s_client -connect enterno.io:443 -servername enterno.io -tls1_2 -no-interactive | Protocol : TLSv1.2 | 0 |
| 10 | Force TLS 1.3 | openssl s_client -connect enterno.io:443 -servername enterno.io -tls1_3 -no-interactive | Protocol : TLSv1.3 | 0 |
| 11 | Probe legacy TLS 1.1 | openssl s_client -connect enterno.io:443 -servername enterno.io -tls1_1 -no-interactive | 40A7D934457F0000:error:0A0000BF:SSL routines:tls_setup_handshake:no protocols available:ssl/statem/s | 1 |
| 12 | Exclude TLS 1.3 | openssl s_client -connect enterno.io:443 -servername enterno.io -no_tls1_3 -no-interactive | Protocol : TLSv1.2 | 0 |
| 13 | Offer h2 and HTTP/1.1 | openssl s_client -connect enterno.io:443 -servername enterno.io -alpn h2,http/1.1 -no-interactive | ALPN protocol: h2 | 0 |
| 14 | Offer HTTP/1.1 | openssl s_client -connect enterno.io:443 -servername enterno.io -alpn http/1.1 -no-interactive | ALPN protocol: http/1.1 | 0 |
| 15 | Offer h2 | openssl s_client -connect enterno.io:443 -servername enterno.io -alpn h2 -no-interactive | ALPN protocol: h2 | 0 |
| 16 | Restrict TLS 1.3 cipher suite | openssl s_client -connect enterno.io:443 -servername enterno.io -tls1_3 -ciphersuites TLS_AES_128_GCM_SHA256 -no-interactive | New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256 | 0 |
| 17 | Offer X25519 | openssl s_client -connect enterno.io:443 -servername enterno.io -groups X25519 -no-interactive | exit 0 | 0 |
| 18 | Offer P-256 | openssl s_client -connect enterno.io:443 -servername enterno.io -groups P-256 -no-interactive | exit 0 | 0 |
Offering h2,http/1.1 selected h2; offering only http/1.1 selected that protocol. A default probe printed No ALPN negotiated because it did not offer ALPN. For cipher or key exchange diagnosis, -ciphersuites narrows TLS 1.3 suites and -groups narrows advertised groups. A passing probe covers this client/server pair, not every client implementation.
If browsers disagree, compare the ALPN result with the HTTP/2 and HTTP/3 guide. The SSL/TLS guide covers the protocol context.

Step 3. Check SNI routing independently of trust
The same IP can serve multiple certificates. We reached 81.163.20.249:443 with SNI enterno.io and verified the site certificate. Without SNI the server delivered TRAEFIK DEFAULT CERT, a self-signed fallback. The non-strict probe still exited 0. That is why a script should not rely on the process status of the default invocation alone.
$ openssl s_client -connect enterno.io:443 -noservername -no-interactive
subject=CN=TRAEFIK DEFAULT CERT
Verify return code: 18 (self-signed certificate)
# exit 0
| № | Purpose | Command | Observed output | exit |
|---|---|---|---|---|
| 19 | Omit SNI | openssl s_client -connect enterno.io:443 -noservername -no-interactive | subject=CN=TRAEFIK DEFAULT CERT | 0 |
| 20 | Dial an IP but retain SNI and name check | openssl s_client -connect 81.163.20.249:443 -servername enterno.io -verify_hostname enterno.io -verify_return_error -no-interactive | Verified peername: enterno.io | 0 |
| 21 | Dial an IP without SNI | openssl s_client -connect 81.163.20.249:443 -noservername -verify_hostname enterno.io -verify_return_error -no-interactive | Verification error: self-signed certificate | 1 |
| 22 | Force IPv4 | openssl s_client -connect enterno.io:443 -servername enterno.io -4 -no-interactive | Connecting to 81.163.20.249 | 0 |
| 23 | Trace TLS state transitions | openssl s_client -connect enterno.io:443 -servername enterno.io -state -no-interactive | SSL_connect:SSLv3/TLS read server session ticket | 0 |
| 24 | Dump received TLS extensions | openssl s_client -connect enterno.io:443 -servername enterno.io -tlsextdebug -no-interactive | TLS server extension "server name" (id=0), len=0 | 0 |
| 25 | Print a summary on exit | openssl s_client -connect enterno.io:443 -servername enterno.io -prexit -no-interactive | Verify return code: 0 (ok) | 0 |
| 26 | Exercise reconnects | openssl s_client -connect enterno.io:443 -servername enterno.io -reconnect -no-interactive | exit 0 | 0 |
When dialing an IP, keep -servername for routing and -verify_hostname for identity. Use -state or -tlsextdebug when the failure occurs before the normal summary. -reconnect exercises repeated connections; it is not a substitute for certificate verification.
Step 4. Confirm failure signatures and non-HTTPS TLS
With strict checking, the BadSSL examples stopped on an expired certificate, an untrusted self-signed certificate, and a hostname mismatch. The final probe tests SMTP STARTTLS on port 587: -starttls smtp performs the SMTP upgrade before beginning TLS. It does not model implicit TLS on port 465.
| № | Purpose | Command | Observed output | exit |
|---|---|---|---|---|
| 27 | Expired certificate | openssl s_client -connect expired.badssl.com:443 -servername expired.badssl.com -verify_return_error -no-interactive | Verification error: certificate has expired | 1 |
| 28 | Self-signed certificate | openssl s_client -connect self-signed.badssl.com:443 -servername self-signed.badssl.com -verify_return_error -no-interactive | Verification error: self-signed certificate | 1 |
| 29 | Wrong certificate name | openssl s_client -connect wrong.host.badssl.com:443 -servername wrong.host.badssl.com -verify_hostname wrong.host.badssl.com -verify_return_error -no-interactive | Verification error: hostname mismatch | 1 |
| 30 | Upgrade SMTP with STARTTLS | openssl s_client -starttls smtp -connect smtp.gmail.com:587 -servername smtp.gmail.com -verify_hostname smtp.gmail.com -verify_return_error -no-interactive | Verified peername: smtp.gmail.com | 0 |
Verification and next action
For the hostname you expect, look for exit 0, Verification: OK, the verified peer name when requested, a negotiated TLS version, and the selected ALPN protocol if your application needs one. For a quick HTTPS certificate and configuration view, run the enterno SSL check; keep the command output when you need to debug the actual handshake.
If it fails
| Observed text | Meaning in this probe | Next check |
|---|---|---|
| hostname mismatch | The certificate does not match the expected name | Compare SNI and -verify_hostname |
| self-signed certificate | The chain is not trusted by this client | Inspect SNI and the CA path |
| no protocols available | This client did not start that protocol | Inspect OpenSSL policy and supported versions |
| No ALPN negotiated | No application protocol was selected here | Offer -alpn h2,http/1.1 |
| OCSP response: no response sent | No stapled response arrived | Check revocation by a separate method |
How we made this
On 13 November 2026, method.py ran 30 commands from a Linux host using OpenSSL 3.5.8. Exact arguments, stdout, stderr, and exit codes are retained in the research data. Targets were public enterno.io, badssl.com, and smtp.gmail.com endpoints. Table cells show diagnostic excerpts, not the entire output. This AI-assisted article uses those recorded measurements; technical conclusions were checked against the saved output and OpenSSL documentation.
FAQ
Why did s_client exit 0 with a bad certificate?
The diagnostic client can continue after a verification error by default. The no-SNI sample did exactly that. Add -verify_return_error for a strict check.
Does -servername validate a hostname?
No. It sends SNI. Use -verify_hostname for the name check.
How can I see the server chain?
Use -showcerts; it lists what the server sent, not every locally trusted root.
Does the TLS 1.1 failure prove a server block?
No. This OpenSSL build rejected the attempt locally before a meaningful server negotiation.