The 60-Second Fix
When a TLS handshake fails with alert unknown ca, the receiver is essentially saying: "I see your certificate, but I have no idea who vouched for it." This usually happens when the machine receiving the certificate doesn't recognize the Certificate Authority (CA) that signed it.
You will likely encounter this during mTLS (Mutual TLS) setups or when using self-signed certificates for internal APIs.
- On the client side: Pass your CA bundle explicitly using
--cacertor install the CA into your system's trust store. - On the server side (mTLS): Verify that your Nginx
ssl_client_certificateor ApacheSSLCACertificateFilepoints to the actual Root CA that signed the user certificates. - Testing only: Use
curl -kto bypass the check, but never do this in production.
Why Is Your Connection Failing?
If you see the error message curl: (35) OpenSSL SSL_connect: alert unknown ca, the handshake hit a wall. One peer sent a "Fatal Alert" to the other. Specifically, unknown_ca means the certificate was received, but the chain of trust is broken because the Root CA is missing from the local trust store.
In standard HTTPS, your browser or curl validates the server. However, in an mTLS setup—common for high-security APIs on port 8443—both sides must verify each other. If you get this error while sending a client certificate, the server is the one rejecting you because it doesn't recognize your issuer.
Real-World Fixes for Common Scenarios
1. Updating the System Trust Store (Linux)
Internal tools often use private CAs. If your local machine doesn't trust your company’s internal CA, you must add it manually to prevent OpenSSL from throwing a fit.
Ubuntu/Debian:
# Move your CA file to the trusted folder
sudo cp internal-ca.crt /usr/local/share/ca-certificates/internal-ca.crt
# Rebuild the certificate store
sudo update-ca-certificates
CentOS/RHEL 7 & 8:
# Copy the file to the anchor directory
sudo cp internal-ca.crt /etc/pki/ca-trust/source/anchors/
# Update the system trust
sudo update-ca-trust extract
2. Fixing mTLS Server Configurations
Are you the admin? If your clients are seeing this alert, your server probably lacks the bundle needed to verify their identities. Even a valid client certificate is useless if the server doesn't have the signer's Root CA on file.
Nginx Setup:
server {
listen 443 ssl;
ssl_certificate /etc/nginx/certs/server.crt;
ssl_certificate_key /etc/nginx/certs/server.key;
# Crucial: This must be the CA that signed your CLIENT certs
ssl_client_certificate /etc/nginx/certs/client-ca.crt;
ssl_verify_client on;
}
Apache Setup:
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/server.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key
# Points to the CA allowed to sign client certs
SSLCACertificateFile /etc/apache2/ssl/client-ca.crt
SSLVerifyClient require
</VirtualHost>
3. Providing CA Bundles Directly to Curl
Modifying system-wide stores isn't always possible, especially in locked-down CI/CD pipelines. Instead, point curl directly to the file it needs. For standard connections, use:
curl --cacert path/to/ca-bundle.crt https://api.internal.dev
For mTLS connections, you need to provide your certificate, your private key, and the CA that validates the server:
curl --cacert server-ca.crt \
--cert client.crt \
--key client.key \
https://mtls.example.com:8443
Deep Diagnostics with OpenSSL
Curl's output can be vague. To see exactly where the handshake dies, use the s_client tool. It provides a verbose look at the certificate exchange.
openssl s_client -connect your-server.com:443 -CAfile my-ca.crt
Scan the output for the Verification status:
Verification: OK: Everything is working perfectly.self signed certificate in certificate chain: You are likely missing the Root CA in your store.unable to get local issuer certificate: An intermediate CA is missing. You need the full chain.
Common Pitfalls to Avoid
- The Intermediate Gap: Many people forget that certificates are often signed by an Intermediate CA, not the Root directly. Ensure your CA bundle includes the full chain (Intermediate + Root).
- Format Issues: OpenSSL prefers PEM (Base64). If your CA is a binary
.ceror.derfile, convert it:openssl x509 -inform der -in cert.cer -out cert.pem. - Permission Denied: Ensure the user running your web server (like
www-dataornginx) actually has read permissions for the.crtand.keyfiles. Achmod 644on certificates is a safe bet.

