Error message
curl: (60) SSL certificate problem: unable to get local issuer certificate
Also printed as
- curl: (60) SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
- SSL certificate problem: unable to get local issuer certificate
OpenSSL-based curl (Linux, macOS Homebrew, Git for Windows) prints this text; newer releases (8.22.0 in our test, while 8.14.1 still used the text above) word it "SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)", adding OpenSSL's verify code. curl built with Schannel on Windows reports the same situation as "schannel: SEC_E_UNTRUSTED_ROOT (0x80090325)", and GnuTLS-based libcurl (used by git on Debian and Ubuntu) as "server verification failed: certificate signer not trusted". Tools built on libcurl, such as PHP and git, print the part after "(60) " with their own prefix.
curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY (20)
What it means
curl received the server's certificates but could not find, in its own CA bundle, the certificate that issued the last one in the chain. The certificate may be perfectly valid; curl simply cannot connect it to any root it trusts, so it refuses the connection (exit code 60). The missing piece is either an intermediate the server forgot to send or a root CA your machine does not have.
Why it happens
The server sends only its own certificate
commonPublic CAs sign server certificates with an intermediate, and the server must send that intermediate along with its leaf. A server configured with cert.pem instead of fullchain.pem works in desktop browsers, which cache intermediates and fetch missing ones, but curl does neither and stops at the leaf.
The certificate comes from a private or corporate CA
commonInternal services, staging environments and Kubernetes ingresses often use certificates from a company CA or a self-made one. That root is not in the public bundle curl uses (/etc/ssl/certs/ca-certificates.crt on Debian and Ubuntu), so nothing it issued can be verified until the root is installed.
A TLS-inspecting proxy re-signs the traffic
occasionalCorporate proxies and endpoint-security products (Zscaler, Netskope, Palo Alto and similar) replace every site's certificate with one issued by their own CA. The browser trusts that CA through the operating system's keychain, while curl, containers and WSL use a separate bundle that lacks it, so every HTTPS call fails the same way.
The machine has no usable CA bundle
occasionalSlim and distroless container images ship without the ca-certificates package, and old systems carry bundles that predate today's roots. With an empty or stale bundle, even certificates for well-known public sites fail with this message.
The CA was added to a store this curl does not read
rareEach curl build reads one particular bundle: Homebrew's curl, a conda environment and Git for Windows each ship their own, and Windows has both Schannel and OpenSSL builds. A CA added to the Windows certificate store or the macOS keychain only reaches the builds that read that store.
How to fix it
- 1.
See what the server actually sends
List the certificates in the handshake. If only one appears (depth 0) and its issuer is an intermediate CA, the server's configuration is incomplete and must be fixed on the server. If the chain ends at a company or self-made root, the client is missing that root.
bash # Which certificates does the server send, and who issued the last one? openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' # 0 s:CN=api.example.com # i:C=US, O=Example Trust Services, CN=Example TLS Issuing CA <- leaf only: intermediate missing - 2.
Fix the server: serve the full chain
Configure the web server with a bundle that contains the leaf followed by every intermediate. This fixes the error for every client at once, including mobile apps and API clients you do not control.
bash # Leaf first, then each intermediate in order; the root itself is optional cat api.example.com.crt intermediate.crt > fullchain.pem # nginx: ssl_certificate /etc/nginx/tls/fullchain.pem; # Apache: SSLCertificateFile /etc/apache2/tls/fullchain.pem # certbot: use live/<name>/fullchain.pem, never cert.pem - 3.
Install a private root CA into the system store
When the chain legitimately ends at a company or internal root, add that root to the operating system's bundle. Get the root from your IT or platform team, or from the CA itself; never from the certificate the failing connection presented, since that is exactly what you cannot yet trust.
bash # Debian, Ubuntu, Alpine (the file must end in .crt) sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt sudo update-ca-certificates # RHEL, Fedora, Amazon Linux sudo cp corp-root-ca.pem /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust - 4.
Point curl at a bundle for one command or one shell
--cacert adds trust for a single call without touching the system; CURL_CA_BUNDLE sets the bundle for every curl call in the environment. The file can hold several PEM certificates.
bash curl --cacert corp-root-ca.pem https://api.example.com/ # or for every curl command in this shell (a file may hold several PEM certificates) export CURL_CA_BUNDLE=/opt/certs/corp-and-public-roots.pem - 5.
Install the CA bundle in minimal containers
If even public sites fail inside a container, the image has no bundle. Install ca-certificates in the image (or copy /etc/ssl/certs/ca-certificates.crt from a build stage) rather than switching verification off.
bash # Debian/Ubuntu-based images apt-get update && apt-get install -y --no-install-recommends ca-certificates # Alpine apk add --no-cache ca-certificates - 6.
Temporary diagnostic: confirm it is a trust problem
-k (--insecure) disables certificate verification, so a successful response only proves the network path works and the failure is about trust. Never leave it in scripts: with -k anyone on the path can read and alter the traffic, including credentials and downloaded code.
bash # Diagnostic only: if this works, the problem is trust, not the network. curl -sS -k -o /dev/null -w '%{http_code}\n' https://api.example.com/
Related errors
curl: (60) SSL certificate problem: self-signed certificate in certificate chaincurl (OpenSSL backend)curl: (60) SSL certificate problem: self-signed certificatecurl (OpenSSL backend)verify error:num=20:unable to get local issuer certificateOpenSSL CLI (openssl s_client / openssl verify)fatal: unable to access 'https://git.example.com/team/app.git/': SSL certificat…git over HTTPS with libcurl + OpenSSL (Git for Windows default, macOS Homebrew, Alpine, RHEL)x509: certificate signed by unknown authorityGo crypto/x509