Skip to content
ecdsa.com
OpenSSLOpenSSL CLI

Error message

SSL routines:ssl3_read_bytes:ssl/tls alert bad certificate

Also printed as

  • SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
  • error:0A000412:SSL routines::ssl/tls alert bad certificate

OpenSSL 3.3 and later print "ssl/tls alert bad certificate", earlier versions "sslv3 alert bad certificate" (code 0A000412; 1.1.1 used 14094412), followed by "SSL alert number 42". OpenSSL clients themselves send unknown_ca (48) or certificate_expired (45) for the same rejections.

OpenSSL — TLS alert 42 (bad_certificate) received from the peer

What it means

The peer sent TLS alert 42 (bad_certificate): it rejected the certificate this side presented. Go's crypto/tls sends this alert for any server certificate it fails to verify (unknown authority, expired, wrong name), so OpenSSL-based servers (nginx, HAProxy, Postfix, s_server) log it whenever a Go client rejects their certificate. In mutual TLS, a server sends it when it rejects the client's certificate.

Why it happens

How to fix it

  1. 1.

    Find the rejecting client and the reason

    The log line names the client address; on that client, the error message gives the real cause. Verifying the chain from outside often shows it directly.

    bash
    # Server log: which client rejected the certificate, and does the chain verify from outside?
    openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null \
      | grep -E 'Verify return code'
  2. 2.

    Go clients: trust the CA or fix the chain

    Serve a complete chain from a trusted CA, or add the private CA to the Go client's RootCAs; never use InsecureSkipVerify as the fix.

    go
    // Go clients: trust the server's CA explicitly (keeps verification on)
    pool, _ := x509.SystemCertPool()
    caPEM, _ := os.ReadFile("internal-ca.pem")
    pool.AppendCertsFromPEM(caPEM)
    client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{RootCAs: pool}}}
  3. 3.

    Mutual TLS: check the client certificate

    Validity dates, issuer and key usage of the client certificate must match what the server expects.

    bash
    # Mutual TLS: check the client certificate the server rejected
    openssl x509 -in client.pem -noout -issuer -dates -ext extendedKeyUsage,keyUsage

Related errors

Browse the full signature error database