jackc/pgx · error

unable to add CA to cert pool

Error message

unable to add CA to cert pool

What it means

Returned by configTLS when x509.CertPool.AppendCertsFromPEM returns false for the sslrootcert file. AppendCertsFromPEM returns false only when the PEM data contains no parseable certificates, so the file is empty, not PEM, or corrupted. The TLS config cannot be built without a valid CA, so connection setup aborts.

Source

Thrown at pgconn/config.go:856

			var err error

			caCertPool, err = x509.SystemCertPool()
			if err != nil {
				return nil, fmt.Errorf("unable to load system certificate pool: %w", err)
			}

			sslmode = "verify-full"
		} else {
			caCertPool = x509.NewCertPool()

			caPath := sslrootcert
			caCert, err := os.ReadFile(caPath)
			if err != nil {
				return nil, fmt.Errorf("unable to read CA file: %w", err)
			}

			if !caCertPool.AppendCertsFromPEM(caCert) {
				return nil, errors.New("unable to add CA to cert pool")
			}
		}

		tlsConfig.RootCAs = caCertPool
		tlsConfig.ClientCAs = caCertPool
	}

	switch sslmode {
	case "disable":
		return []*tls.Config{nil}, nil
	case "allow", "prefer":
		tlsConfig.InsecureSkipVerify = true
	case "require":
		// According to PostgreSQL documentation, if a root CA file exists,
		// the behavior of sslmode=require should be the same as that of verify-ca
		//
		// See https://www.postgresql.org/docs/current/libpq-ssl.html
		if sslrootcert != "" {

View on GitHub (pinned to ec1a0befd2)

Solutions

  1. Ensure sslrootcert points to a PEM-encoded CA certificate bundle (BEGIN CERTIFICATE blocks).
  2. If you have a DER cert, convert it: 'openssl x509 -inform der -in ca.der -out ca.pem'.
  3. Verify the file with 'openssl x509 -in ca.pem -noout -text' before using it.
  4. Use sslrootcert=system to rely on the OS trust store when appropriate.

Example fix

# before: pointed at a DER file or wrong file
sslrootcert=/etc/ssl/db-ca.der

# after: PEM-encoded CA
openssl x509 -inform der -in /etc/ssl/db-ca.der -out /etc/ssl/db-ca.pem
sslrootcert=/etc/ssl/db-ca.pem
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the sslrootcert file is valid PEM with at least one cert before connecting.
func validateRootCertPEM(path string) error {
    data, err := os.ReadFile(path)
    if err != nil {
        return err
    }
    pool := x509.NewCertPool()
    if !pool.AppendCertsFromPEM(data) {
        return fmt.Errorf("%s contains no PEM-encoded certificates", path)
    }
    return nil
}

Try / catch

if _, err := pgx.ParseConfig(dsn); err != nil {
    if strings.Contains(err.Error(), "unable to add CA to cert pool") {
        return fmt.Errorf("sslrootcert is not valid PEM; convert DER->PEM or fix the file: %w", err)
    }
}

Prevention

When it happens

Trigger: Setting sslrootcert to a path whose contents are not valid PEM certificates (e.g. a DER-encoded cert, a private key file, random text, or an empty file). Read succeeds but AppendCertsFromPEM fails.

Common situations: Pointing sslrootcert at a .key file by mistake; downloading a cert in DER instead of PEM; cert file truncated to zero bytes; copy-paste error inserting the cert into the file.

Related errors


AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04). Data as JSON: /data/errors/4258dd45bc41421e.json. Report an issue: GitHub.