Fetch a certificate from a live server

To fetch a server's certificate, run `openssl s_client -connect example.com:443 -servername example.com </dev/null`. The `-servername` flag sends SNI and is essential — without it a virtual-hosted server answers with its default certificate, so you inspect the wrong one. Add `-showcerts` to see the full chain the server sends, and pipe the output through `openssl x509` to decode it. The `</dev/null` closes stdin so the command exits instead of waiting for input.

Updated August 19, 2026 Verified against OpenSSL 3.5.7

The basic command #

Connect and show what the server presents
openssl s_client -connect example.com:443 -servername example.com </dev/null

Replace these values

PlaceholderWhat to put there
-connect host:portWhere to connect. Port 443 for HTTPS.
-servername hostSends SNI. Omit this and you may inspect the wrong certificate.
&lt;/dev/nullCloses stdin so the command exits rather than waiting for input.

Just the certificate, decoded #

Pipe the leaf certificate into x509
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
Expected output
subject=CN = example.com
issuer=C = US, O = Example CA, CN = Example Intermediate CA
notBefore=Aug 16 00:00:00 2026 GMT
notAfter=Nov 14 23:59:59 2026 GMT
X509v3 Subject Alternative Name:
  DNS:example.com, DNS:www.example.com

Saving the certificate to a file #

Save just the server certificate
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -out example.com.crt

Saving the whole chain #

-showcerts prints every certificate the server sent. Extract them all with sed:

Save the full chain as the server presents it
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
| sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' \
> chain.pem

Then inspect what came back:

openssl crl2pkcs7 -nocrl -certfile chain.pem | openssl pkcs7 -print_certs -noout

Reading the verification result #

The last useful line of s_client output is the verdict:

Just the verdict
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| grep "Verify return code"
Expected output
Verify return code: 0 (ok)
Code Meaning Page
0 (ok) Chain validated against your trust store —
10 Certificate has expired expiry
18 Self-signed certificate self-signed vs CA-signed
19 Self-signed certificate in chain that error
20 Unable to get local issuer certificate that error
21 Unable to verify the first certificate incomplete chain

Counting what the server sends #

A quick way to spot a missing intermediate. A publicly trusted site should send at least two:

How many certificates came back?
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
| grep -c "BEGIN CERTIFICATE"
Expected output
2

Other protocols #

SMTP with STARTTLS
openssl s_client -connect mail.example.com:587 -starttls smtp </dev/null
IMAP, PostgreSQL, LDAP
openssl s_client -connect mail.example.com:143 -starttls imap </dev/null
openssl s_client -connect db.example.com:5432 -starttls postgres </dev/null
openssl s_client -connect ldap.example.com:389 -starttls ldap </dev/null

Pinning down the TLS version #

Adding a version flag constrains the handshake, which is how you find out what a server still accepts:

Force a specific protocol version
openssl s_client -connect example.com:443 -servername example.com -tls1_2 </dev/null

A handshake failure here is the expected result when the server has disabled that version — but on OpenSSL 3 it can equally be your own client refusing to make the offer. Interrogating versions and cipher suites properly is its own job: see check which TLS versions a server supports.

Checking a server that is not yet live #

To test a certificate before DNS points at the new host, resolve elsewhere but keep SNI honest:

Connect to an IP while presenting the real hostname
openssl s_client -connect 203.0.113.10:443 -servername example.com </dev/null

Frequently asked questions

Why do I need </dev/null?
s_client opens an interactive session and waits on stdin so you can type an HTTP request by hand. Redirecting from /dev/null closes stdin immediately, so the command prints its output and exits — which is what you want in a script.
What does -servername actually do?
It sends the Server Name Indication TLS extension, telling the server which hostname you are asking for. On shared hosting, omitting it means the server replies with its default certificate and you end up debugging a certificate nobody uses.
How do I check a mail server or another protocol?
Use -starttls. For example openssl s_client -connect mail.example.com:587 -starttls smtp. It also supports imap, pop3, ftp, xmpp, ldap and postgres.
Why does verification fail here but work in my browser?
Browsers repair incomplete chains by caching intermediates and fetching missing ones over HTTP. OpenSSL does neither, so it fails where a browser succeeds. The server is genuinely misconfigured — see that error.

References