Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Automation By James Joyner IV · · 9 min read

curl Error: '(60) SSL certificate problem: unable to get local issuer certificate' — Cause, Fix, and Troubleshooting Guide

Quick answer

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
Free toolkit

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 -v shows 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 / --insecure in 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_client chain output, not the browser.
  • Serving only the leaf certificate is the single most common cause; always deploy the full chain (fullchain.pem), never cert.pem alone.
  • Clock skew masquerades as a chain/expiry error — check date -u before 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.
Free download · 368-page PDF

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.