Skip to content
ecdsa.com
Python ssl module (OpenSSL)Python cryptography

Error message

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate

Also printed as

  • [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate

Python appends the C source location, e.g. "(_ssl.c:1082)". Not to be confused with "self-signed certificate in certificate chain", which means a CA chain ending in an untrusted root. OpenSSL 1.1.1 spells it "self signed".

Python ssl module (OpenSSL) — ssl.SSLCertVerificationError, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT (18)

What it means

The server presented a single self-signed certificate (its issuer is itself) that is not in this context's trusted CA set. There is no CA to look up, so OpenSSL fails at depth 0. Typical for development servers, appliances and fresh installs; the remedy is to trust that certificate deliberately or to replace it.

Why it happens

How to fix it

  1. 1.

    Trust this one certificate for this client

    Load the server's own certificate as cafile. Hostname and date checks stay on, and only this exact certificate is accepted.

    python
    import ssl, urllib.request
    
    # Trust exactly this certificate (fetched and fingerprint-checked out of band)
    ctx = ssl.create_default_context(cafile="api.example.com.pem")
    urllib.request.urlopen("https://api.example.com:8443/", context=ctx)
  2. 2.

    Fetch the certificate and check its fingerprint

    Compare the SHA-256 fingerprint with the value shown on the device's console or by its administrator before trusting the file.

    bash
    openssl s_client -connect api.example.com:8443 -servername api.example.com </dev/null 2>/dev/null \
      | openssl x509 -out api.example.com.pem
    openssl x509 -in api.example.com.pem -noout -fingerprint -sha256   # compare with the server's console
  3. 3.

    Development: use a local CA instead

    A local CA lets you trust one root and issue properly signed certificates for every dev host, so no client needs per-certificate exceptions.

    bash
    # Development: one local CA, many certificates (mkcert installs the CA for you)
    mkcert -install
    mkcert api.example.test
    export SSL_CERT_FILE="$(mkcert -CAROOT)/rootCA.pem"
  4. 4.

    Temporary diagnostic: turn verification off in a test

    check_hostname = False and CERT_NONE disable every check and accept any certificate, including one presented by an attacker. Use it only to confirm that trust is the only problem, then remove it.

    python
    # Temporary diagnostic only: proves trust is the sole problem. Never ship this.
    import ssl
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

Related errors

Browse the full signature error database