When a Java application connects to an HTTPS endpoint, the connection can fail before the application sends its actual request. Instead of receiving an HTTP response, you may see errors such as SSLHandshakeException, PKIX path building failed, or unable to find valid certification path to requested target.
These errors usually mean that Java could not establish a trusted TLS connection with the remote server. The cause may be an expired certificate, a missing intermediate certificate, an outdated truststore, or a server that presents a certificate for the wrong hostname.
The challenge is identifying which part of the TLS connection is failing. Repeatedly changing certificates or disabling verification can hide the real problem and introduce security risks.
This article explains how to investigate Java TLS handshake errors, inspect certificates, check truststores, and fix common configuration problems.
1. Understand What Happens During a TLS Handshake
TLS protects data exchanged between a Java application and a remote service. During the handshake, the client and server negotiate connection settings and establish encryption keys. The client also checks the server's certificate to determine whether it can trust the server's identity.
A simplified connection process looks like this:
The Java application connects to the server.
The server presents its certificate and any intermediate certificates it sends.
Java checks the certificate chain against its configured trust anchors.
Java validates relevant certificate properties, including validity dates and hostname identity.
If the checks succeed, the TLS connection can be established.
A failure during certificate validation can prevent the application from making an HTTPS request.
For example, this Java code may fail during the connection:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class TlsClient {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com"))
.GET()
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}If the server certificate cannot be validated, the request may fail before an HTTP status code is returned.
The exact exception and its nested cause provide important clues about what went wrong.
2. Read the Full Exception Before Changing Anything
Start by collecting the complete exception, including its nested causes.
Common errors include:
Error | Possible cause |
|---|---|
| A general failure during the TLS handshake |
| Java could not build a trusted certificate path |
| No acceptable trust path was found |
| The certificate does not match the requested hostname |
| A certificate has passed its validity period |
| The client and server could not agree on a supported TLS protocol version |
| A general handshake failure that may involve protocols, cipher suites, certificates, or server configuration |
These messages are not interchangeable. For example, a hostname mismatch requires a different fix from a missing intermediate certificate.
Look at the deepest relevant Caused by section in the stack trace. It often identifies the validation step that failed.
Do not assume that every SSLHandshakeException is caused by a bad certificate. Protocol incompatibility, client-certificate requirements, cipher configuration, and other TLS settings can also cause handshake failures.
3. Check the Server Certificate with OpenSSL
Before changing the Java application, inspect the remote server's certificate chain.
If OpenSSL is available, run:
openssl s_client \
-connect api.example.com:443 \
-servername api.example.com \
-showcerts \
-verify_return_errorReplace the hostname with the actual server name.
The -connect option specifies the network endpoint. The -servername option sends the hostname through Server Name Indication (SNI), which helps the server select the correct certificate when several sites share an IP address.
The -showcerts option displays the certificates sent by the server. The -verify_return_error option makes verification errors fail the connection instead of simply reporting them.
Look for verification errors near the end of the output.
For example, an output indicating that an issuer certificate cannot be found may suggest an incomplete chain or a trust problem. However, the exact meaning depends on the error code and verification depth.
Also remember that OpenSSL and Java may use different trust stores. A successful OpenSSL check does not guarantee that the same connection will work in Java.
If OpenSSL cannot connect at all, investigate DNS, routing, firewall rules, proxy settings, and whether the service is listening on the expected port.
4. Check Whether the Certificate Has Expired
A certificate is valid only during its configured validity period. If the server presents an expired certificate, Java may reject the connection.
You can inspect the certificate dates with OpenSSL:
openssl s_client \
-connect api.example.com:443 \
-servername api.example.com \
</dev/null 2>/dev/null \
| openssl x509 -noout -datesExample output:
notBefore=Oct 1 00:00:00 2026 GMT
notAfter=Dec 30 23:59:59 2026 GMTCompare these dates with the current date and time. Also check the system clock on the machine running Java because an incorrect clock can make a valid certificate appear not yet valid or expired.
If the server certificate has expired, renew and deploy the certificate on the server or load balancer. Importing an expired certificate into a Java truststore is not the right solution.
5. Understand Java Truststores
Java uses trusted certificates to determine which certificate authorities it accepts when validating a remote server's certificate chain.
A common truststore is the cacerts file included with a JDK or JRE distribution. Its location varies by Java installation.
You can check which Java executable is being used:
java -versionTo see the runtime configuration, run:
java -XshowSettings:properties -versionLook for properties such as java.home and, if configured, javax.net.ssl.trustStore.
Java may use a truststore explicitly configured through system properties. If no custom truststore is configured, the runtime generally uses its default truststore locations and behavior.
A custom truststore might be specified like this:
java \
-Djavax.net.ssl.trustStore=/opt/app/certs/truststore.p12 \
-Djavax.net.ssl.trustStorePassword=changeit \
-Djavax.net.ssl.trustStoreType=PKCS12 \
-jar application.jarThe password shown is an example only. Do not place real truststore passwords directly in shell history, scripts, source control, or process arguments where other users may be able to inspect them. Use an appropriate secret-management mechanism for your environment.
Also, a truststore password protects access to the store; it does not make an untrusted certificate trustworthy by itself.
6. Inspect the Truststore with keytool
Java's keytool utility can list certificates stored in a Java-compatible truststore.
For example:
keytool -list -v \
-keystore /opt/app/certs/truststore.p12 \
-storetype PKCS12If the store is password-protected, keytool will prompt for the password unless one is supplied through an option.
Look for the expected trusted certificate and check its owner, issuer, validity period, and entry type.
If you need to inspect a particular alias, use:
keytool -list -v \
-keystore /opt/app/certs/truststore.p12 \
-storetype PKCS12 \
-alias company-root-caA common mistake is updating one Java installation's truststore while the application runs using another JDK or a different container image.
Confirm the runtime used by the actual application process, not just the Java version shown in your interactive terminal.
7. Fix a Missing Certificate Authority or Intermediate Certificate
Java may report PKIX path building failed when it cannot construct a valid chain from the server's certificate to a trusted root.
There are several possible causes:
The server does not send a required intermediate certificate.
The required certificate authority is missing from the Java truststore.
A custom truststore replaced the default truststore but does not contain the necessary trust anchors.
The server presents a certificate chain that is not valid for the intended trust configuration.
First, inspect the chain presented by the server. If an intermediate certificate is missing, the preferred fix is usually to configure the server to present the complete required chain.
If the endpoint uses a private certificate authority, obtain the correct CA certificate from a trusted administrator or the organization's certificate-management system. Verify its fingerprint or other trusted distribution information before importing it.
You can then import the CA certificate into a dedicated truststore:
keytool -importcert \
-alias company-root-ca \
-file company-root-ca.pem \
-keystore truststore.p12 \
-storetype PKCS12Keytool will prompt for the truststore password and may ask you to confirm trust.
Only approve the certificate after verifying that it is the intended CA certificate. Do not import a certificate simply because it appeared in a failed connection.
If the truststore is intended only for one application, a dedicated truststore can be easier to maintain than modifying a shared JDK installation.
8. Check for a Hostname Mismatch
A certificate may be valid and issued by a trusted CA but still fail because it does not identify the hostname used by the application.
For example, the application connects to:
https://api.example.comBut the certificate may be issued only for:
internal.example.comModern TLS hostname validation checks the certificate's Subject Alternative Name entries. The hostname in the URL must match an appropriate DNS name or IP address entry in the certificate.
Inspect the certificate:
openssl s_client \
-connect api.example.com:443 \
-servername api.example.com \
</dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -ext subjectAltNameCheck whether the expected hostname appears in the Subject Alternative Name extension.
The best fix is to use the correct hostname or deploy a certificate that covers the hostname clients actually use. Avoid disabling hostname verification because that removes an important part of TLS server authentication.
9. Enable Java TLS Debugging
If the certificate and truststore appear correct, Java's TLS debugging output can reveal more about the handshake.
Start the application with:
java \
-Djavax.net.debug=ssl,handshake,trustmanager \
-jar application.jarThe output can show handshake messages, trust-manager decisions, certificate details, and protocol negotiation.
Use this option carefully. TLS debugging can produce a large amount of output and may expose connection metadata or certificate information. Avoid enabling it indefinitely in production, and protect the resulting logs.
For an application launched by a service manager or container platform, configure the JVM option in the actual application startup settings. Adding it to an unrelated terminal command will not affect an already running process.
Review the logs for:
The certificate chain presented by the server.
Trust-manager messages about accepted or rejected certificates.
The TLS protocol version negotiated or attempted.
Errors involving client certificates or cipher-suite negotiation.
The point where the handshake terminates.
If the failure is caused by protocol or cipher incompatibility, check the Java runtime version and the server's TLS configuration. Prefer supported TLS versions and cipher suites rather than enabling obsolete protocols to make the connection work.
10. Common Mistakes to Avoid
Disabling certificate validation
Some developers work around handshake errors by installing a trust manager that accepts every certificate or by disabling hostname verification.
This makes the application vulnerable to connecting to an impostor server. It should not be used as a production fix.
Importing the server's leaf certificate without understanding the chain
Trusting a specific leaf certificate can create certificate-rotation and maintenance problems. Understand whether the application should trust a private CA, use the system truststore, or rely on a properly configured server chain.
Assuming the operating system and Java trust stores are identical
Java's default trust configuration depends on the runtime and its configuration. A certificate trusted by a browser or operating system may not be trusted by the Java process.
Changing several settings at once
Replacing the truststore, changing TLS protocols, and disabling verification simultaneously makes it difficult to identify the actual cause. Test one hypothesis at a time.
Conclusion
Java TLS handshake errors become easier to resolve when you separate certificate validation, truststore configuration, hostname verification, and protocol negotiation.
Start with the full exception, inspect the server's certificate chain, confirm which Java runtime and truststore the application uses, and enable TLS debugging when the cause remains unclear.
Fix the specific problem rather than bypassing certificate validation. A correctly configured certificate chain, an appropriate truststore, and proper hostname verification allow Java applications to establish secure connections without weakening TLS security.

Join the conversation! Your thoughts help the community grow.