I was debugging why HTTPS requests to app.example.com were failing with certificate errors. The certificate on the server was valid, but clients were getting “certificate name mismatch” errors. Turns out the server hosted multiple domains on the same IP, and I was getting the wrong certificate. SNI solved it.
What is SNI? Link to heading
Server Name Indication (SNI) is a TLS extension that lets a server host multiple SSL certificates on a single IP address. The client sends the hostname in the initial TLS handshake, and the server responds with the correct certificate.
Without SNI, the server just sends its “default” certificate, which might not match the domain you’re requesting.
Basic connection test Link to heading
openssl s_client -connect example.com:443
This works for simple cases, but if the server uses SNI (most do nowadays), you might get the wrong certificate.
With SNI (the right way) Link to heading
openssl s_client -connect example.com:443 -servername example.com
The -servername flag is crucial for SNI. Without it, you might get the wrong certificate and wonder why your domain doesn’t work.
Real debugging scenario Link to heading
Here’s what happened to me:
I was setting up a new Ingress in Kubernetes for api.example.com. The certificate was issued by cert-manager and looked correct in the secret. But curl was failing:
curl https://api.example.com
curl: (60) SSL certificate problem: certificate subject name mismatch
First, I checked if the certificate existed on the server:
echo | openssl s_client -connect api.example.com:443 2>/dev/null | openssl x509 -noout -subject
Output:
subject= /CN=default.example.com
Wrong certificate! The server was sending the default certificate instead of the one for api.example.com.
Then I tested with SNI:
echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null | openssl x509 -noout -subject
Output:
subject= /CN=api.example.com
Correct certificate! This confirmed the certificate existed but curl wasn’t using SNI properly. Turns out the client was an old version of curl without SNI support. Upgrading curl fixed it.
Useful commands Link to heading
Show the full certificate chain:
openssl s_client -connect example.com:443 -servername example.com -showcerts
This dumps all certificates in the chain. Useful for debugging intermediate certificate issues.
Check certificate expiry:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
Output:
notBefore=Dec 1 00:00:00 2025 GMT
notAfter=Feb 28 23:59:59 2026 GMT
Check the Subject Alternative Names (SANs):
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -text | grep -A 1 "Subject Alternative Name"
This shows which domains the certificate is valid for.
Verify the certificate chain:
openssl s_client -connect example.com:443 -servername example.com -verify_return_error
If the chain is invalid, this command exits with an error.
Quiet mode (just show errors):
openssl s_client -connect example.com:443 -servername example.com -quiet
Test against a specific IP (useful when DNS isn’t set up yet):
openssl s_client -connect 1.2.3.4:443 -servername app.example.com
This connects to the IP but sends the SNI hostname. Great for testing before changing DNS.
Common certificate issues Link to heading
1. Certificate name mismatch Link to heading
Error: certificate subject name mismatch
Cause: The certificate doesn’t include the domain you’re connecting to.
Fix: Check the SANs on the certificate:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -text | grep DNS:
If your domain isn’t listed, the certificate is wrong.
2. Expired certificate Link to heading
Error: certificate has expired
Cause: Certificate validity period has passed.
Fix: Check the dates:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
Renew the certificate if it’s expired.
3. Self-signed certificate Link to heading
Error: self signed certificate in certificate chain
Cause: Certificate is self-signed or signed by an untrusted CA.
Fix: Either trust the CA, or replace the certificate with one from a trusted CA (like Let’s Encrypt).
For testing, you can skip verification:
curl -k https://example.com
But never do this in production.
4. Intermediate certificate missing Link to heading
Error: unable to get local issuer certificate
Cause: Server isn’t sending the full certificate chain.
Fix: Check the chain:
openssl s_client -connect example.com:443 -servername example.com -showcerts
You should see multiple certificates. If you only see one, the intermediate certificate is missing. Configure the server to include it.
5. Wrong certificate on SNI server Link to heading
Error: Certificate looks wrong or is for a different domain.
Cause: You’re not using -servername.
Fix: Always use -servername when testing domains with SNI:
openssl s_client -connect example.com:443 -servername example.com
Testing tools Link to heading
These tools are easier to use than raw OpenSSL for some tasks:
SSL Labs Server Test: Comprehensive SSL/TLS testing. Shows certificate details, protocol support, vulnerabilities. Recommended for all public-facing domains.
testssl.sh: Command-line tool for testing SSL/TLS. More comprehensive than OpenSSL s_client.
testssl.sh https://example.com
- sslscan: Another CLI tool for SSL/TLS testing.
sslscan example.com:443
- curl with -v: Shows SSL handshake details.
curl -v https://example.com 2>&1 | grep -A 10 "SSL connection"
Quick reference Link to heading
# Test with SNI
openssl s_client -connect example.com:443 -servername example.com
# Check expiry
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
# Check subject
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject
# Check SANs
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -text | grep DNS:
# Test against IP with SNI
openssl s_client -connect 1.2.3.4:443 -servername example.com
# Show full chain
openssl s_client -connect example.com:443 -servername example.com -showcerts
The echo | at the start sends an empty input so the command exits after connecting. Otherwise s_client waits for input.
Resources Link to heading
- OpenSSL s_client manual
- SSL Labs Server Test
- testssl.sh documentation
- Mozilla SSL Configuration Generator - generates secure SSL configs for various servers
- Certificate Decoder - paste a certificate to decode it