Skip to content
ecdsa.com
nginx error log / OpenSSLOpenSSL CLI

Error message

SSL_do_handshake() failed (SSL: error:0A000418:SSL routines::tlsv1 alert unknown ca:SSL alert number 48)

Also printed as

  • SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
  • error:0A000418:SSL routines::tlsv1 alert unknown ca

nginx logs it at info level as "SSL_do_handshake() failed (SSL: error:0A000418:SSL routines::tlsv1 alert unknown ca:SSL alert number 48) while SSL handshaking, client: …". The openssl CLI prints "…:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca:…". OpenSSL clients send this alert for untrusted, self-signed and incomplete chains alike.

nginx error log / OpenSSL — TLS alert 48 (unknown_ca) received from the peer

What it means

The other side of the connection aborted the handshake with TLS alert 48 (unknown_ca): it could not chain the certificate it received to a CA it trusts. In a server log (as here, from nginx) it means a client refused the server's certificate. On a client it means the server refused the client certificate in mutual TLS. The side that logs the alert is never the side that has the problem: the cause lies with the certificate sent to the peer.

Why it happens

How to fix it

  1. 1.

    Work out which certificate was rejected

    In a server log, test the server's chain from outside; on a client running mutual TLS, check the client certificate against the CA the server expects.

    bash
    # In a SERVER log: a client rejected the server's certificate (e.g. missing intermediate)
    openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
      | grep -E '^ *[0-9]+ s:|^ *i:|Verify return code'
    # On a CLIENT: the server rejected your client certificate (mutual TLS)
  2. 2.

    Server: serve a complete, publicly trusted chain

    For public endpoints, use a certificate from a public CA and configure the full chain. For internal endpoints, make sure every client has the internal root.

    text
    # nginx: the chain clients need, leaf first
    ssl_certificate     /etc/nginx/tls/fullchain.pem;
    ssl_certificate_key /etc/nginx/tls/privkey.pem;
  3. 3.

    Mutual TLS: issue client certificates from the trusted CA

    Verify the client certificate against the CA the server is configured with (ssl_client_certificate in nginx), and send the client's intermediate along with its certificate.

    bash
    # Mutual TLS: is the client certificate issued by the CA the server trusts?
    openssl verify -CAfile server-trusted-client-ca.pem -untrusted client-intermediate.pem client.pem
    # Send the client's intermediate too, if it has one
    cat client.pem client-intermediate.pem > client-chain.pem
    curl --cert client-chain.pem --key client.key https://mtls.example.com/

Related errors

Browse the full signature error database