OpenTelemetry Error Guide: 'x509: certificate is valid for ... not ...' — Fix OTLP TLS Hostname Mismatch
Fix 'x509: certificate is valid for collector.internal, not otel.example.com': SAN mismatch. Use the right DNS name or server_name_override.
- #opentelemetry
- #observability
- #troubleshooting
- #errors
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
This error appears when the TLS handshake succeeds cryptographically but the server certificate’s Subject Alternative Names (SANs) do not include the hostname the exporter connected to. The client trusts the CA, yet refuses the identity. It shows up in SDK stderr and in the Collector’s otlp exporter logs:
error exporterhelper/queue_sender.go:128 Exporting failed. Dropping data. {"kind": "exporter", "data_type": "traces", "name": "otlp", "error": "rpc error: code = Unavailable desc = connection error: desc = \"transport: authentication handshake failed: x509: certificate is valid for collector.internal, not otel.example.com\""}
The HTTP/OTLP variant reads:
traces export: Post "https://otel.example.com:4318/v1/traces": tls: failed to verify certificate: x509: certificate is valid for collector.internal, not otel.example.com
x509: certificate is valid for collector.internal, not otel.example.com means the endpoint host (otel.example.com) is not listed in the certificate’s SANs (which only cover collector.internal) — an identity mismatch, not an untrusted-CA or expiry problem.
Symptoms
- Every export fails with a hostname mismatch; the CA itself is trusted, so it is not an “unknown authority” error.
- The error names two hosts: what the cert is valid for, and what you connected to.
- Connecting by the cert’s real SAN (e.g.
collector.internal) works, while the alias or IP fails. - The exporter endpoint uses an IP address or a DNS alias not present in the cert SANs.
openssl s_client ... -verify_hostnameconfirms the mismatch.- Setting
server_name_overrideto the cert’s SAN clears the error.
Common Root Causes
- Endpoint host not in the cert SANs — the exporter targets
otel.example.combut the cert only listscollector.internal. - Connecting by IP — the endpoint is
10.0.7.9:4317and the cert has no IP SAN for that address. - DNS alias / CNAME — a friendly alias points at the Collector, but the cert was issued for the backend’s real name.
- Load balancer or shared cert — the LB presents a cert for its own hostname, not the OTLP service name clients use.
- Legacy CN-only certificate — the cert relies on a Common Name with no SANs, which modern Go TLS clients reject outright.
- Cert reused across environments — a
collector.internalcert copied to a service that clients reach asotel.example.com.
Diagnostic Workflow
First inspect the certificate the endpoint actually presents and list its SANs:
# Print the SANs the server cert covers
openssl s_client -connect otel.example.com:4317 -servername otel.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -text | grep -A1 'Subject Alternative Name'
Compare that list to the host in your exporter endpoint:
echo "$OTEL_EXPORTER_OTLP_ENDPOINT" # the host here must appear in the SANs above
env | grep OTEL_EXPORTER_OTLP
The correct fix is almost always to connect by a name the certificate is valid for. Point the exporter at the cert’s real SAN:
exporters:
otlp:
endpoint: collector.internal:4317 # a name present in the cert SANs
tls:
insecure: false
ca_file: /etc/otelcol/certs/server-ca.crt
When you must keep an alias or IP endpoint (for example, connecting via an LB VIP), use server_name_override so verification checks the cert against the SAN name instead of the dialed host:
exporters:
otlp:
endpoint: 10.0.7.9:4317 # IP or alias with no matching SAN
tls:
insecure: false
ca_file: /etc/otelcol/certs/server-ca.crt
server_name_override: collector.internal # verify against this SAN
Reserve insecure_skip_verify for short-lived debugging only — it disables identity checks entirely and must never be shipped. The clean fix is either the right name or server_name_override. Validate and confirm:
otelcol-contrib validate --config /etc/otelcol/config.yaml
journalctl -u otelcol-contrib --since '10 min ago' | grep -i 'certificate is valid for\|x509\|handshake'
Example Root Cause Analysis
A platform team fronted their gateway Collector with an internal load balancer and told application teams to export to otel.example.com:4317. The server certificate, however, had been issued for the backend hostname collector.internal and carried no SAN for the alias. Every exporter that used the friendly name failed with x509: certificate is valid for collector.internal, not otel.example.com, and traces silently stopped.
Two fixes were viable, and the team applied the durable one. Short term, exporters that could not be re-issued quickly set server_name_override: collector.internal so TLS verification matched the cert’s SAN while still dialing the alias — no security downgrade, since the CA and identity were still checked. Long term, the certificate was reissued with both collector.internal and otel.example.com (plus the LB VIP as an IP SAN) in the SAN list, after which the override was removed and every client verified cleanly against the alias.
Prevention Best Practices
- Issue Collector certificates with SANs covering every name and IP clients actually use, including LB aliases and VIPs.
- Prefer connecting by a real DNS SAN over an IP address; add IP SANs only when IP endpoints are unavoidable.
- Use
server_name_overrideas a deliberate, documented bridge — neverinsecure_skip_verifyin production. - Keep certificates environment-specific; do not reuse a
collector.internalcert for a service clients reach by another name. - Automate cert issuance (cert-manager or your CA tooling) so SAN lists stay in sync with endpoints as they change.
- Add a startup check that runs
openssl s_client -verify_hostnameagainst the intended endpoint before rollout.
Quick Command Reference
# List the SANs the server cert actually covers
openssl s_client -connect otel.example.com:4317 -servername otel.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -text | grep -A1 'Subject Alternative Name'
# Verify the hostname explicitly
openssl s_client -connect otel.example.com:4317 -verify_hostname otel.example.com </dev/null
# Confirm the endpoint host the exporter uses
env | grep OTEL_EXPORTER_OTLP
# Validate config after setting the right name or server_name_override
otelcol-contrib validate --config /etc/otelcol/config.yaml
Conclusion
x509: certificate is valid for collector.internal, not otel.example.com is an identity mismatch: the CA is trusted but the endpoint host is missing from the certificate’s SANs. The right fix is to connect by a name the cert covers, or, when an alias or IP endpoint is unavoidable, to set server_name_override to the SAN so verification stays intact. Avoid insecure_skip_verify outside of momentary debugging. Best of all, reissue the certificate with SANs for every name and IP clients use, and the mismatch never recurs.
Related
- OpenTelemetry Error Guide: ‘x509: certificate signed by unknown authority’
- OpenTelemetry Error Guide: ‘connection refused’ to the Collector
- OpenTelemetry Error Guide: ‘context deadline exceeded’
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.