<!-- https://pkizerotohero.com/errors/openssl-tlsv1-alert-unknown-ca/ | Markdown mirror of the HTML page | PKI Zero to Hero, by Duyutech BV -->

> Fix OpenSSL's tlsv1 alert unknown ca (SSL alert 48): find out which side sent it, then fix the CA the peer trusts or the chain you send.

Source: https://pkizerotohero.com/errors/openssl-tlsv1-alert-unknown-ca/ · Last reviewed: 2026-10-20

- OpenSSL
- Exact text checked with the real tool

# tlsv1 alert unknown ca

Also seen in: curl, Python, nginx, Apache httpd, HAProxy, Envoy, Java (unknown\_ca)

**In one sentence:**

The other side of the connection rejected your certificate because it does not trust the CA that issued it: usually a client certificate in mutual TLS, sometimes your server's certificate.

[Check yours: Chain checker](https://pkizerotohero.com/tools/chain/)

## Where you see it

In OpenSSL and everything built on it, on whichever side **received** the alert. As a client in [mutual TLS](https://pkizerotohero.com/handbook/glossary/#mutual-tls):

```text
$ openssl s_client -connect api.example.com:443 -cert client.pem -key client.key
...
2C7F0000:error:0A000418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca:../openssl-3.2.3/ssl/record/rec_layer_s3.c:909:SSL alert number 48
```

curl shows it as `curl: (56) OpenSSL SSL_read: OpenSSL/3.0.13: error:0A000418:SSL routines::tlsv1 alert unknown ca, errno 0` (code 35 over TLS 1.2), and Python as `ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca`. OpenSSL 1.1.1 numbers it `error:14094418`. On a **server**, the same line appears in the error log when a client rejected the server’s certificate.

The reason string is OpenSSL’s `SSL_R_TLSV1_ALERT_UNKNOWN_CA` ([OpenSSL error list](https://github.com/openssl/openssl/blob/master/crypto/err/openssl.txt)).

## What it means

TLS peers can end a handshake with an alert. Alert 48, `unknown_ca`, means: “A valid certificate chain or partial chain was received, but the certificate was not accepted because the CA certificate could not be located or could not be matched with a known trust anchor” (RFC 9846, [section 6.2](https://www.rfc-editor.org/rfc/rfc9846#section-6.2)). In “tlsv1 alert”, “tlsv1” is only OpenSSL’s historical prefix; it does not mean TLS 1.0 was used.

The key question is **who sent it**. The side that logs this message is the one whose certificate was rejected. If you are the client, the server did not accept your [client certificate](https://pkizerotohero.com/handbook/glossary/#client-certificate). If you are the server, a client did not accept yours.

## Likely causes

### Your client certificate comes from a CA the server does not trust

The most common case: a client certificate from the wrong CA, a test CA, or a new CA the server was never told about. **Confirm** which CAs the server accepts; it lists them in its certificate request:

```bash
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null | grep -A3 'Acceptable client certificate CA names'
openssl x509 -in client.pem -noout -issuer
```

```text
Acceptable client certificate CA names
O=Example Corp, CN=Example Client CA
```

**Fix:** get a client certificate from one of the listed CAs, or, if you run the server, add your client CA to the file it trusts for clients:

```text
# nginx
ssl_client_certificate /etc/nginx/client-ca.pem;
ssl_verify_client on;

# Apache httpd
SSLCACertificateFile /etc/httpd/client-ca.pem
SSLVerifyClient require
```

See [How to set up mutual TLS](https://pkizerotohero.com/guides/mutual-tls-setup/).

### You send your client certificate without its intermediate

If the server trusts only the root, it needs your intermediate to build the chain, and the client must send it. **Confirm** that the server’s CA file and your intermediate verify your certificate:

```bash
openssl verify -CAfile server-trusted-root.pem -untrusted client-intermediate.pem client.pem
```

**Fix:** put your certificate and the intermediate in one file and use it as the client certificate (`cat client.pem client-intermediate.pem > client-chain.pem`, then `--cert client-chain.pem` in curl or `-cert_chain` in `s_client`).

### Clients reject your server’s certificate

If the message is in your **server’s** log, OpenSSL-based clients refused your certificate, usually because you do not send the intermediate or because they do not have your private root. Java clients send `certificate_unknown` instead, which OpenSSL logs as `sslv3 alert certificate unknown` (`ssl/tls alert certificate unknown` in 3.2 and later). **Confirm** what you send with `openssl s_client -showcerts`, and **fix** the chain: [How to build the full chain file your server needs](https://pkizerotohero.com/guides/build-fullchain/). For a private CA, install its root on the clients.

Warning

Do not turn off verification on either side

`ssl_verify_client optional_no_ca` on the server, or `verify=False` and `-k` on clients, make the alert go away by accepting certificates nobody checked. For mutual TLS, that removes the very check the setup exists for. Fix which CA is trusted, or the chain that is sent.

## Check yours

*Interactive tool: Chain checker (runs in the browser at [/tools/chain/](https://pkizerotohero.com/tools/chain/))*

Paste the certificate chain you send (your client chain, or your server’s from `openssl s_client -showcerts`). The checker shows whether the intermediate is there and which root the chain needs.

## Learn why

- [Both sides show ID: mutual TLS](https://pkizerotohero.com/handbook/mutual-tls/): how the server asks for and checks client certificates.
- [Certificate chains and path validation](https://pkizerotohero.com/handbook/certificate-chains/): why the intermediate must be sent.
- Related: Java’s [handshake\_failure](https://pkizerotohero.com/errors/java-handshake-failure/) and [curl: (35)](https://pkizerotohero.com/errors/curl-35-ssl-connect-error/).

**Early edition.** Checked against the standards; an independent expert review is in progress. Found a mistake? [Tell us](https://pkizerotohero.com/contact/?topic=content-error&page=/errors/openssl-tlsv1-alert-unknown-ca/).

Last reviewed 20 October 2026Edition 0.9

## Learn why it happens

- [Chapter 23: Both sides show ID: mutual TLS](https://pkizerotohero.com/handbook/mutual-tls/)
- [Chapter 12: Who do we trust? CAs, trust stores and self-signed certificates](https://pkizerotohero.com/handbook/trust-stores/)
- [Chapter 13: Certificate chains and path validation](https://pkizerotohero.com/handbook/certificate-chains/)

## Fix it step by step

- [How to set up mutual TLS (nginx and curl)](https://pkizerotohero.com/guides/mutual-tls-setup/)

## Everything on this topic

- [Chains and trust stores](https://pkizerotohero.com/topics/chains-and-trust/)
- [TLS and HTTPS](https://pkizerotohero.com/topics/tls/)
- [Private PKI](https://pkizerotohero.com/topics/private-pki/)
