How to Solve javax.net.ssl.SSLHandshakeException

If you encounter javax.net.ssl.SSLHandshakeException while developing or deploying Java applications on WildFly, Spring Boot, Quarkus, or microservices, it often indicates a mismatch between your client and server TLS configurations. This exception can result from expired certificates, missing trusted CA certificates, or unsupported TLS versions (TLS 1.0/1.1 being deprecated and disabled by default in modern JDKs) in your JVM or server configuration. In this updated guide, you will learn practical, step-by-step methods to diagnose and solve SSLHandshakeException in Java, ensuring your applications remain secure and compliant with modern TLS 1.2 and TLS 1.3 standards while maintaining connectivity to HTTPS endpoints.

Connecting Securely to a Server

To connect securely to a server, you first need to get the server's public certificate. Save the certificate in a file and add it to your computer's list of trusted certificates. This list of trusted certificates is the trust store and you can find it located in a file cacerts. In JDK 9 and later this file lives under $JAVA_HOME/lib/security/cacerts (older JDK 8 installations used $JAVA_HOME/jre/lib/security/cacerts).

To add the certificate to the trust store, you need to run a program called keytool with the certificate file, a meaningful name, and the path to the cacerts file.

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

Once you have completed these steps, you can communicate securely with the server provided that both JVMs (client/server) are using the following properties with the correct values:

java -Djavax.net.ssl.keyStore=path_to_keystore_file \
     -Djavax.net.ssl.keyStorePassword=password \
     -Djavax.net.ssl.trustStore=path_to_truststore_file \
     -Djavax.net.ssl.trustStorePassword=password MyClass

If you have followed the above steps and you are facing javax.net.ssl.SSLHandshakeException then you need to check for some possible causes.

Causes of the Issue

Here are some possible solutions to fix the issue javax.net.ssl.SSLHandshakeException:

  1. You need to update your SSL/TLS protocol version: Make sure that you're using the latest SSL/TLS protocol version that your web server supports. Some older versions of SSL/TLS are no longer secure and may result in handshake failures. Consider upgrading to TLS 1.2 or, preferably, TLS 1.3, which offers a faster handshake and stronger default cipher suites.
  2. You need to install SSL/TLS certificates: Ensure that you have a valid SSL/TLS certificate installed on your web server. This certificate should be issued by a trusted certificate authority (CA) and should be valid for the domain name that you're accessing. You can use online tools like SSL Checker to verify the validity of your SSL/TLS certificate.
  3. Wrong SSL/TLS configuration: Ensure that your SSL/TLS configuration is correct and matches the settings of your SSL/TLS certificate. If you're using a self-signed certificate, make sure that you've installed it on your client device as well. If you're unsure about your SSL/TLS configuration, you can use online tools like SSL Labs to diagnose any issues.
  4. Disable outdated SSL/TLS protocols: Disable outdated SSL/TLS protocols like SSLv3 or TLS 1.0/1.1 that are no longer secure. Modern JDKs (8u+ with recent updates, 11, 17, 21, 25) already disable these by default via the jdk.tls.disabledAlgorithms security property, but it's worth verifying your server configuration explicitly as well.
  5. Disable cipher suites with weak encryption: Disable cipher suites with weak encryption that are no longer secure. This will help prevent handshake failures and improve the security of your website. You can do this by modifying your web server configuration.

Troubleshooting and Solution

When you set the system property javax.net.debug=ssl,handshake, it enables debug logging for SSL/TLS connections, including detailed information about the handshake process. This debug logging can help you determine whether a handshake failure is caused by the client or the server:

-Djavax.net.debug=ssl,handshake

Another option is to use JInfo to see SSL/TLS Properties of the Java process.

The jinfo command allows you to view the system properties of the process. For example, if the PID of your process is 12345, you can use the following command to view the system properties:

jinfo -sysprops 12345

This will output a list of all system properties set for your Java process, including the value of javax.net.ssl.trustStore.

Look for the javax.net.ssl.trustStore property in the output and verify that it's set to the expected value. For example, if you expect the trustStore to be set to /path/to/truststore, look for a line in the output that looks like this:

javax.net.ssl.trustStore=/path/to/truststore

By using the jinfo command to verify the runtime system properties, you can ensure that your Java application or server is using the correct SSL/TLS trustStore at runtime.

A Test Class to Check SSL Connectivity

Finally, you can try to reproduce the SSLHandshakeException locally programmatically. This can be useful, for example, if your Client application uses unsupported Cipher suites. By enabling them in your code, you can determine if that is the root cause.

Here is a sample Java Class you can use to test SSL Connectivity:

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

public class SSLConnectivityTest {

    public static void main(String[] args) throws Exception {

        // Set the SSL socket factory
        SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();

        // Set the SSL socket
        SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket("your.server.com", 443);

        // Enable all supported cipher suites
        String[] enabledCipherSuites = sslSocket.getSupportedCipherSuites();
        sslSocket.setEnabledCipherSuites(enabledCipherSuites);

        // Start the SSL handshake
        sslSocket.startHandshake();

        // Get the input and output streams of the SSL socket
        InputStream inputStream = sslSocket.getInputStream();
        OutputStream outputStream = sslSocket.getOutputStream();

        // Write data to the SSL socket
        outputStream.write("Hello, server!\n".getBytes());

        // Read data from the SSL socket
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line = reader.readLine();
        System.out.println("Server response: " + line);

        // Close the SSL socket
        sslSocket.close();
    }
}

Make sure you are running the above class with the KeyStore/TrustStore System Properties:

java -Djavax.net.ssl.keyStore=path_to_keystore_file \
     -Djavax.net.ssl.keyStorePassword=password \
     -Djavax.net.ssl.trustStore=path_to_truststore_file \
     -Djavax.net.ssl.trustStorePassword=password SSLConnectivityTest

Using OpenSSL to Test a Remote Connection

Besides, you can also use openssl as Client to debug the remote connection to a secure Host. For example:

openssl s_client -debug -connect www.server.com:443

You can use the openssl tool to verify some use cases, such as if your Java Client is not sending the SNI (Server Name Indication) extension to a SSL/TLS endpoint. You can add the SNI to the openssl tool to verify if this solves the issue as follows:

openssl s_client -debug -connect www.server.com:443 -servername www.server.com

To specifically force and test a TLS 1.3 handshake with openssl, you can add the -tls1_3 flag:

openssl s_client -tls1_3 -debug -connect www.server.com:443 -servername www.server.com

WildFly, Spring Boot and Quarkus Specific Checks

Besides the generic JVM-level checks above, each runtime has its own place where TLS settings can silently drift out of sync with your certificates:

  • WildFly / JBoss EAP: verify the elytron subsystem's key-store, trust-store, and ssl-context definitions, and confirm the protocols attribute of your server-ssl-context includes TLSv1.2 and TLSv1.3 only.
  • Spring Boot: check server.ssl.trust-store, server.ssl.key-store, and server.ssl.enabled-protocols in application.properties or application.yml, especially after upgrading to Spring Boot 3.x, which defaults to TLS 1.3 where the underlying JDK supports it.
  • Quarkus: review quarkus.tls.* (the unified TLS registry introduced in recent Quarkus versions) or the legacy quarkus.http.ssl.* properties, and make sure your native image build includes the required security providers if you compile to a GraalVM native executable.

Production Readiness, Kubernetes and OpenShift Considerations

SSL handshake failures often surface differently — and are harder to reproduce — once an application moves from a developer laptop to a containerized, multi-service production environment. A few practices help keep TLS issues manageable at scale:

  • Centralize certificate management with cert-manager on Kubernetes/OpenShift, so certificates are automatically issued, mounted as Secrets, and renewed before expiry instead of relying on manually imported keystores.
  • Terminate TLS at the edge using an Ingress Controller, OpenShift Route, or a service mesh (Istio, OpenShift Service Mesh) so individual pods don't each need custom trust store configuration for east-west traffic.
  • Mount trust stores as ConfigMaps/Secrets rather than baking custom CA certificates into container images, so a CA rotation doesn't require rebuilding and redeploying every image.
  • Monitor certificate expiry proactively with Prometheus alerts on certificate lifetime, rather than waiting for a handshake failure in production logs.
  • Enable readiness/liveness probes over HTTPS carefully, ensuring the probe's HTTP client trusts the same CA chain as external callers, a common source of confusing false-negative probe failures after enabling mutual TLS.

Alternative Approaches

In conclusion, this article was a walkthrough of common issues you might face when connecting applications through a secure connection. It is worth mentioning some alternative approaches which can offload the complexity of your secure applications:

  1. Use Let's Encrypt or ACME clients (or cert-manager on Kubernetes/OpenShift) to automate certificate renewals, reducing expired cert issues.
  2. Migrate applications to TLS 1.3 where possible for better security and handshake performance; disable TLS 1.0/1.1 entirely since both are deprecated and unsupported by modern browsers and JVMs.
  3. For APIs, use API gateways (Keycloak, Kong, NGINX) or a service mesh to handle TLS termination, offloading complexity from the JVM while maintaining secure connections.

Frequently Asked Questions

What causes javax.net.ssl.SSLHandshakeException in Java?

It's usually caused by an expired or untrusted server certificate, a missing CA certificate in the client's trust store, a mismatched or unsupported TLS protocol version between client and server, or an incompatible cipher suite. Enabling -Djavax.net.debug=ssl,handshake is the fastest way to pinpoint which of these applies to your case.

How do I fix "PKIX path building failed" together with SSLHandshakeException?

This sub-error means the client's trust store doesn't contain the certificate authority that issued the server's certificate. Import the missing CA (or the full chain) into your trust store with keytool -import, or point -Djavax.net.ssl.trustStore to a trust store that already contains it.

Should I still support TLS 1.0 or TLS 1.1?

No. TLS 1.0 and 1.1 are deprecated, disabled by default in modern JDKs and browsers, and generally fail compliance requirements such as PCI-DSS. Standardize on TLS 1.2 as a minimum and prefer TLS 1.3 wherever your client and server support it.

How can I check which TLS protocols and ciphers a server supports?

Use openssl s_client -connect host:443 -tls1_2 or -tls1_3 to force a specific protocol, or an online tool like SSL Labs' SSL Server Test to get a full report of supported protocols, cipher suites, and certificate chain issues.

Why does my application work in the browser but fail with SSLHandshakeException in Java?

Browsers ship their own, frequently updated CA bundles and are more permissive about incomplete certificate chains served by misconfigured servers. The JVM trust store is separate and stricter, so a server that omits intermediate certificates may work in a browser but fail in a Java client until the trust store is corrected or the server is fixed to send the full chain.

Does this apply the same way to WildFly, Spring Boot, and Quarkus?

The underlying cause and JVM-level diagnostics (trust store, TLS version, cipher suites) are the same across all three. Where they differ is configuration surface: WildFly uses the elytron subsystem, Spring Boot uses server.ssl.* properties, and Quarkus uses quarkus.tls.* or quarkus.http.ssl.*.

Can a firewall or proxy cause an SSLHandshakeException?

Yes. A TLS-inspecting proxy or firewall that re-signs traffic with its own certificate is a common cause, especially in corporate networks. If the proxy's CA isn't imported into the client's trust store, the handshake will fail exactly like an untrusted certificate issue.

Is mutual TLS (mTLS) affected by the same troubleshooting steps?

Mostly yes, but with an extra dimension: the server must also trust the client's certificate. If you enable mTLS and start seeing handshake failures, check both directions — the client's trust store for the server's CA, and the server's trust store for the client's CA — since either one being incomplete will break the handshake.


Recommended Articles

Secure Your Applications with WildFly 2025: Configuring HTTPS and Managing Certificates

Learn how to configure HTTPS on WildFly in 2025, using secure TLS protocols and modern certificate management tools. #WildFly #Java #SSLWizard #TLS #SecurityStandards

Fixing the Jenkins SSLHandshakeException with a Valid JDK Certificate

Learn how to solve the common issue of the Jenkins SSL Handshake Exception caused by a missing or invalid certificate in your JDK. Get step-by-step instructions for resolving this error and ensuring secure plugin installation.

Configure Transport Layer Security (TLS) v.1.3 on WildFly Application Server

Learn how to enable TLS 1.3 on WildFly application server for improved encryption and security, with reduced latency and deprecated feature removal.

Mastering Common Elytron Commands in Modern WildFly Releases

Discover essential Elytron commands for modern WildFly, including Credential Stores, Key Stores, Trust Stores, SSL/TLS, and more. #WildFly #JavaSecurity #Elytron