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

> Java throws No subject alternative names present when you connect by IP and the certificate has no SAN. Connect by hostname or reissue with an IP SAN.

Source: https://ssl.sh/errors/java-no-subject-alternative-names-present/
Last updated: 2026-11-10

**`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:

```bash
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**:

```bash
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:

```bash
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](https://ssl.sh/tools/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](https://ssl.sh/tools/self-signed-certificate-generator/), and inspect the result with the [certificate decoder](https://ssl.sh/tools/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.
