Programming languages

Java "No subject alternative names present": how to fix

By · Last verified

Error messagejava.security.cert.CertificateException: No subject alternative names present

No subject alternative names present means Java tried to match the host you connected to against the certificate's Subject Alternative Name (SAN) extension, and the certificate has no SAN at all. Usually you connect by IP address (for example https://203.0.113.10:8443) to a certificate that names only a hostname, or to an old certificate with only a Common Name.

Quick fix

Connect by a hostname the certificate lists, or reissue it with the IP as a SAN.

Look at the certificate's SAN list:

openssl s_client -connect 203.0.113.10:8443 </dev/null 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
  • If it lists DNS:api.example.com, connect with that hostname instead of the IP. If there is no DNS record yet, add one (or an /etc/hosts entry for testing).
  • If there is no SAN at all, or you must use the IP, reissue the certificate with the IP address as an IP SAN:
openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
  -keyout server.key -out server.crt -subj "/CN=api.internal.example.com" \
  -addext "subjectAltName=DNS:api.internal.example.com,IP:203.0.113.10"

That example is self-signed; in production sign it with your internal CA so clients only need to trust one root.

Causes

1. Connecting by IP to a hostname certificate

Java's HTTPS hostname check (RFC 2818 style) matches IP addresses only against IP Address SAN entries, never against DNS names or the Common Name.

  • Confirm: the URL in your code or config contains an IP; the certificate has DNS SANs only.
  • Fix: use the hostname. In Kubernetes or Docker, use the service DNS name rather than a pod or container IP.

2. Legacy certificate with only a Common Name

Older self-signed and internal certificates were often generated with only CN=... and no SAN extension. Many clients have stopped accepting that.

  • Confirm: openssl x509 -noout -ext subjectAltName prints nothing.
  • Fix: reissue with SAN. With keytool:
keytool -genkeypair -alias server -keyalg EC -groupname secp256r1 -validity 365 \
  -dname "CN=api.internal.example.com" \
  -ext "SAN=dns:api.internal.example.com,ip:203.0.113.10" \
  -keystore server.p12 -storetype PKCS12

3. Wrong SAN for the IP in use

If the message is No subject alternative names matching IP address 203.0.113.10 found, the certificate has SANs but not this IP, for example after the server moved to a new address. Add the new IP or switch to a hostname.

4. Hostname mismatch variants

No subject alternative DNS name matching api.example.com found is the hostname version of the same check. The certificate is for a different name; reissue it with the correct names, using the CSR generator to make sure the SAN list is complete.

Fixes by environment

In every client, connect by a name the certificate lists, or reissue the certificate with the IP in its SAN.

Spring RestTemplate / WebClient, Apache HttpClient, OkHttp: all use the same hostname rules. Change the base URL to the hostname; do not plug in a no-op hostname verifier.

JDBC and message brokers: PostgreSQL, MySQL, Kafka and RabbitMQ clients that verify hostnames show equivalent errors. Make the connection string use the name in the certificate.

Kubernetes: API servers and webhooks need the service DNS names (for example my-svc.my-namespace.svc) in their certificate SANs; tools such as cert-manager set this through the dnsNames field.

Self-signed test certificates: generate them with SANs from the start, for example with the self-signed certificate generator, and inspect the result with the certificate decoder.

Don't do this

  • HttpsURLConnection.setDefaultHostnameVerifier((h, s) -> true). It disables hostname checks for the entire JVM, not only your call.
  • -Djdk.internal.httpclient.disableHostnameVerification for the java.net.http client. It is an internal testing switch and turns off the same protection.
  • Adding the server's leaf certificate to the truststore to "fix" it. The error is about names, not trust, and remains.

FAQ

Why does it work with the hostname but not with the IP address?

When you connect by hostname, Java compares the name with the DNS entries in the certificate's SAN extension. When you connect by IP, it looks only for IP-address SAN entries. A normal certificate for example.com has no IP entry, so the IP connection fails.

Can a public CA issue a certificate for an IP address?

Some can. Let's Encrypt lists IP identifiers as supported only for its shortlived profile, whose certificates are valid for about 160 hours, so renewal must be fully automated. For private addresses such as 10.x or 192.168.x, no public CA can issue; use an internal CA.

Does Java still fall back to the Common Name?

For DNS hostnames, Java's HTTPS hostname check can still fall back to the Common Name when the certificate has no DNS SAN, but other clients (Go, Chrome) no longer do. For IP addresses, Java requires an IP SAN. Put every name and IP in the SAN extension.

Is setting a HostnameVerifier that returns true acceptable for internal services?

No. Without hostname verification, any certificate signed by a CA you trust is accepted for any server, so one stolen or misissued internal certificate can impersonate every service. Fix the certificate instead.

Sources

  1. Java Secure Socket Extension (JSSE) Reference Guide
  2. keytool (Java SE 21 tool reference)
  3. RFC 5280: Internet X.509 PKI Certificate and CRL Profile
  4. Let's Encrypt: Profiles