curl Error: '(60) SSL certificate problem: unable to get local issuer certificate' — Cause, Fix, and Troubleshooting Guide
Fix curl: (60) SSL certificate problem: unable to get local issuer certificate — missing intermediate CA, stale client CA bundle, internal CAs, and clock skew.
- #automation
- #troubleshooting
- #curl
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
curl exit code 60 is a TLS verification failure: the connection was established and the server presented a certificate, but curl could not build a trusted chain from that certificate up to a root CA it trusts. The specific text unable to get local issuer certificate means one link in the chain is missing — curl has the server (leaf) cert but not the intermediate CA that signed it, or it does not trust the root at the top.
$ curl -v https://api.example.com/health
* Server certificate:
* subject: CN=api.example.com
* issuer: CN=Example Intermediate CA
* SSL certificate problem: unable to get local issuer certificate
* Closing connection
curl: (60) SSL certificate problem: unable to get local issuer certificate
There are two sides to this: the server may be misconfigured (not sending its intermediate CA in the handshake), or the client may be missing an up-to-date CA bundle (or the CA is a private/internal one it was never told to trust). Both produce the identical message. The correct fix is almost always to complete trust properly — not to disable verification with -k, which turns an integrity failure into a silent security hole.
Symptoms
curl: (60) SSL certificate problem: unable to get local issuer certificate.curl -vshows the handshake reaching the certificate stage, then failing on verification.- Browsers may work (they cache intermediates) while curl and other CLI clients fail — a classic sign the server is not sending its full chain.
- The same URL works from one host but not another (different or outdated CA bundles).
- Fails right after deploying behind a new internal CA or a TLS-terminating proxy.
curl -sS -o /dev/null -w '%{http_code}\n' https://api.example.com/health; echo "exit: $?"
exit: 60
Common Root Causes
1. Server omits the intermediate CA from its chain
The server sends only the leaf certificate. Clients that do not already cache the intermediate cannot build the chain. This is the most common cause and is a server misconfiguration.
2. Missing or outdated CA bundle on the client
The host’s trust store (ca-certificates) is stale or absent, so even a public root is not trusted.
ls -l /etc/ssl/certs/ca-certificates.crt
ls: cannot access '/etc/ssl/certs/ca-certificates.crt': No such file or directory
3. Private / internal CA not trusted by the client
An internal PKI signed the cert; the corporate root CA was never installed in the host trust store.
4. A TLS-intercepting (MITM) proxy
A corporate proxy re-signs traffic with its own CA. curl does not trust that CA, so verification fails.
5. Clock skew
If the host clock is wrong, a valid certificate can appear not-yet-valid or expired, which can surface as a verification failure. Always check the clock.
6. Wrong or truncated bundle passed with —cacert
An explicit --cacert pointing at a file that lacks the needed root/intermediate produces the same error.
How to Diagnose
Step 1: Inspect the chain the server actually sends
openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
| grep -E 's:|i:'
0 s:CN=api.example.com
i:CN=Example Intermediate CA
Only one certificate (0 s: / i:) in the output means the server is not sending the intermediate — a server-side chain problem.
Step 2: Ask openssl to verify and read the result
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null \
| grep -E 'Verify return code'
Verify return code: 20 (unable to get local issuer certificate)
Code 20 mirrors curl’s message and confirms a broken/incomplete chain.
Step 3: Check the client CA bundle exists and is current
ls -l /etc/ssl/certs/ca-certificates.crt
curl-config --ca 2>/dev/null || echo "using system default"
A missing or tiny bundle points at a client-side trust problem rather than the server.
Step 4: Verify the host clock
date -u
timedatectl status | grep -E 'System clock|NTP'
Tue Jul 12 09:41:12 UTC 2026
System clock synchronized: yes
A clock off by hours or days can make a valid cert fail validation.
Step 5: Detect a MITM proxy
openssl s_client -connect api.example.com:443 </dev/null 2>/dev/null | grep -E 'issuer|i:'
An issuer like CN=Corp Proxy CA instead of the expected public/internal CA reveals interception.
Fixes
Fix the server (preferred when the server is yours)
Serve the full chain — leaf plus intermediates — not just the leaf. With most tools that means using the fullchain.pem file:
# nginx
ssl_certificate /etc/ssl/api.example.com/fullchain.pem; # leaf + intermediates
ssl_certificate_key /etc/ssl/api.example.com/privkey.pem;
Verify from a clean client afterward:
openssl s_client -connect api.example.com:443 -showcerts </dev/null 2>/dev/null | grep -c 'BEGIN CERTIFICATE'
2
Two or more certificates means the chain is now complete.
Fix the client trust store
Update the CA bundle:
sudo apt-get update && sudo apt-get install -y ca-certificates
sudo update-ca-certificates
Install a private/internal or corporate-proxy root CA into the trust store:
sudo cp corp-root-ca.crt /usr/local/share/ca-certificates/corp-root-ca.crt
sudo update-ca-certificates
Point curl at a specific bundle when you cannot modify the system store:
curl --cacert /etc/ssl/api.example.com/fullchain.pem https://api.example.com/health
Fix clock skew:
sudo timedatectl set-ntp true
What to Watch Out For
- Do NOT reach for
-k/--insecurein automation. It disables verification entirely and hides real MITM or expiry problems. The only defensible use is an explicit, documented internal endpoint where you instead pin the internal CA with--cacert. - Browsers cache intermediates, so a site that “works in Chrome” can still fail in curl — trust the
openssl s_clientchain output, not the browser. - Serving only the leaf certificate is the single most common cause; always deploy the full chain (
fullchain.pem), nevercert.pemalone. - Clock skew masquerades as a chain/expiry error — check
date -ubefore assuming the CA is wrong. - A corporate MITM proxy means every host must trust the proxy’s CA; bake it into base images rather than patching per-host.
Related Guides
- curl (7) Failed to connect after N ms: Connection refused
- curl (28) Operation timed out
- Webhook 401 invalid signature
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.