- Java
- Exact text checked with the real tool
Received fatal alert: handshake_failure
Also seen in: Spring, Apache HttpClient, OkHttp on the JVM, Maven, Gradle, Tomcat, Kafka clients
In one sentence
The server refused the TLS handshake Java offered: usually no shared cipher suite, or the server wants a client certificate that Java did not send.
Where you see it
In any Java program that opens a TLS connection: HttpsURLConnection, java.net.http.HttpClient, Spring’s RestTemplate and WebClient, Apache HttpClient, JDBC drivers, Kafka clients, and build tools such as Maven and Gradle.
javax.net.ssl.SSLHandshakeException: (handshake_failure) Received fatal alert: handshake_failure
Java 23 and later, and recent updates of Java 17 and 21, put the alert name in brackets in front, as above. Older versions, including current Java 8 and 11, print only Received fatal alert: handshake_failure. The text comes from OpenJDK’s Alert.java. Frameworks wrap it, so search the stack trace for SSLHandshakeException.
What it means
“Received” is the key word: the server sent a fatal handshake_failure alert and closed the TLS handshake. Java is not complaining about the server’s certificate; that would be PKIX path building failed. In RFC 9846, the alert means the sender “was unable to negotiate an acceptable set of security parameters given the options available” (section 6.2). In practice the server found no cipher suite it shares with Java, or it wanted a client certificate and got none.
To see where it stops, run the program once with Java’s TLS debug output:
java -Djavax.net.debug=ssl:handshake -jar app.jar
javax.net.ssl|DEBUG|10|main|2026-10-20 04:12:57.967 CEST|null:-1|Produced ClientHello handshake message (
javax.net.ssl|DEBUG|10|main|2026-10-20 04:12:57.976 CEST|null:-1|Received alert message (
"level" : "fatal",
"description": "handshake_failure"
An alert straight after the ClientHello points to versions or cipher suites. An alert after a CertificateRequest points to the client certificate.
Likely causes
No cipher suite in common
The server accepts only cipher suites that this Java version does not offer, or the other way round. Current Java updates disable many old suites in jdk.tls.disabledAlgorithms, including TLS_RSA_* (we found it in Java 11, 17, 21 and 25 builds from 2026; Java 8 still allowed it). A server that offers only those suites then fails with exactly this error.
Confirm which suites the server accepts, and look at Java’s list:
openssl s_client -connect api.example.com:443 -servername api.example.com -tls1_2 </dev/null 2>/dev/null | grep 'Cipher is'
grep -A6 '^jdk.tls.disabledAlgorithms' "$JAVA_HOME/conf/security/java.security"
On Java 8 the file is $JAVA_HOME/jre/lib/security/java.security (or lib/security in a JRE).
Fix it on the server: enable TLS 1.2 with ECDHE and AES-GCM or ChaCha20-Poly1305 suites, and TLS 1.3. See How to configure TLS securely. If the server is very old and cannot be changed, put a modern reverse proxy in front of it.
The server wants a client certificate
With mutual TLS, the server asks for a client certificate. Java sends one only if its keystore holds a key whose certificate was issued by one of the CAs the server lists as acceptable. If none matches, Java sends an empty certificate message, and the server fails the handshake, typically with handshake_failure in TLS 1.2 and certificate_required in TLS 1.3. With TLS 1.2 the debug output shows the line below; with TLS 1.3 it shows No available client authentication scheme.
No X.509 certificate for client authentication, use empty Certificate message instead
Confirm which CAs the server accepts:
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null | grep -A3 'Acceptable client certificate CA names'
Fix: point Java at a keystore with the right key and certificate chain, issued by one of those CAs:
java -Djavax.net.ssl.keyStore=client.p12 -Djavax.net.ssl.keyStoreType=PKCS12 -Djavax.net.ssl.keyStorePassword=changeit -jar app.jar
Include the intermediate in the PKCS #12 file, and check that the certificate has not expired. See How to set up mutual TLS.
The server only speaks an old TLS version
Then the alert is usually protocol_version rather than handshake_failure, but some servers send handshake_failure for this too. Confirm with openssl s_client -tls1_2 and -tls1_3; fix by enabling TLS 1.2 and 1.3 on the server.
Check yours
Paste the exception or the last debug lines. The finder shows the matching page, so you can tell a handshake problem from a certificate problem.
Learn why
- The TLS 1.3 handshake: how the client and server agree on versions and cipher suites.
- Both sides show ID: mutual TLS: how a server asks for client certificates.
- Related: ERR_SSL_VERSION_OR_CIPHER_MISMATCH and tlsv1 alert unknown ca.
Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.