Programming languages
Java No appropriate protocol: SSLHandshakeException fixed
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate) means Java has no TLS version left that it is allowed to use. Each enabled protocol is disabled by the JDK security policy or lacks a usable cipher suite. The error occurs before Java contacts the server; code that pins TLS 1.0 or 1.1 is the usual cause.
What the error means
Java found no TLS version that is both enabled and usable, so it never sent a ClientHello. When a handshake starts, JSSE builds its list of "active protocols": the enabled protocols (from SSLContext, setEnabledProtocols, jdk.tls.client.protocols or a library setting) that are not blocked by jdk.tls.disabledAlgorithms and that have at least one enabled cipher suite that works with them. If that list is empty, HandshakeContext throws this exact exception. No ClientHello is sent.
Since JDK 8u291 (April 20, 2021), 11.0.11 and 16, jdk.tls.disabledAlgorithms contains TLSv1 and TLSv1.1. Any code that asks only for those versions now ends up with an empty list. Newer JDKs disable more: Oracle's crypto roadmap notes that TLS_RSA cipher suites are disabled in JDK 24 and later, so code that pins only such suites fails the same way.
Compare this with a related message. If your client enables TLS 1.2/1.3 but the server can only do TLS 1.0, the handshake gets further and fails with The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]. Different message, different side to fix.
Causes, most common first
Code or configuration that pins TLS 1.0 or 1.1 is the most common cause.
1. Code or a library pins TLSv1 or TLSv1.1
Typical forms: SSLContext.getInstance("TLSv1"), socket.setEnabledProtocols(new String[] {"TLSv1"}), HTTP client builders with a protocol array, -Dhttps.protocols=TLSv1, mail properties such as mail.smtp.ssl.protocols=TLSv1, or a JDBC URL parameter that limits TLS versions in an older driver.
- Confirm: search code and configuration:
grep -rnE "TLSv1([^.]|\.1)|SSLv3|https\.protocols|ssl\.protocols|enabledTLSProtocols|tlsVersions" src/ config/ *.properties *.yml 2>/dev/null
Then run once with -Djavax.net.debug=ssl:handshake and look for No available cipher suite for ... or ignored protocols.
- Fix: remove the pin and use
SSLContext.getInstance("TLS"), which lets the JDK enable the newest versions it supports (TLS 1.3 and 1.2 on current releases). Upgrade old drivers and libraries that hardcode TLS 1.0.
2. A Java server is configured with old protocols only
Tomcat, Jetty or Spring Boot configured with something like server.ssl.enabled-protocols=TLSv1 fails on the server side for every client after a JDK update.
- Fix:
server.ssl.enabled-protocols=TLSv1.3,TLSv1.2in Spring Boot, or list onlyTLSv1.2andTLSv1.3in theprotocolsattribute of Tomcat'sSSLHostConfig.
3. Pinned cipher suites that are disabled or do not fit
"Cipher suites are inappropriate" covers code that sets enabled cipher suites to a list where nothing is usable: only TLS_RSA_* suites on JDK 24+, only 3DES or RC4 suites, or only TLS 1.3 suites while TLS 1.3 is not enabled. Look them up in the cipher suite lookup.
- Fix: stop pinning cipher suites in application code, or pin modern ECDHE AEAD suites.
4. A hardened or custom java.security
A company image, FIPS configuration or -Djava.security.properties file may disable more than the default.
- Confirm:
grep -n -A4 "^jdk.tls.disabledAlgorithms" "$JAVA_HOME/conf/security/java.security" # JDK 9+
grep -n -A4 "^jdk.tls.disabledAlgorithms" "$JAVA_HOME/jre/lib/security/java.security" # JDK 8
ps -ef | grep -o "java.security.properties=[^ ]*"
Fix commands by platform
Remove the TLS 1.0 or 1.1 pin and let the JDK negotiate TLS 1.2 or 1.3.
Any OS, JVM options for a client:
java -Djdk.tls.client.protocols=TLSv1.3,TLSv1.2 -Dhttps.protocols=TLSv1.3,TLSv1.2 -jar app.jar
Code:
SSLContext ctx = SSLContext.getInstance("TLS"); // not "TLSv1"
ctx.init(null, null, null); // default trust store, verification on
Spring Boot (application.properties):
server.ssl.enabled-protocols=TLSv1.3,TLSv1.2
Windows services: JVM options usually live in the service wrapper configuration (for Tomcat, the Java tab of tomcat9w.exe or the JAVA_OPTS of the service); add the same -D flags there.
The remote system supports only TLS 1.0: the correct fix is upgrading that system. As a temporary, scoped exception, give only that JVM an override file:
# /opt/app/legacy-tls.security
# Paste the exact jdk.tls.disabledAlgorithms value from your JDK's java.security,
# then delete only "TLSv1," and "TLSv1.1," from it. Keep every other entry.
jdk.tls.disabledAlgorithms=SSLv3, DTLSv1.0, RC4, DES, <...rest of your JDK's list...>
java -Djava.security.properties=/opt/app/legacy-tls.security -jar app.jar
With a single =, the file appends to the master java.security and wins for the keys it defines, for this process only.
Don't disable certificate verification
Installing a trust-all TrustManager, setting a HostnameVerifier that returns true, or importing random certificates into cacerts does nothing for this error, because the handshake never starts. Those changes only make the application accept forged certificates, exposing credentials and data to anyone on the network path.
Also avoid editing the JDK's global java.security to remove TLSv1: every Java application on the machine then accepts deprecated protocols. The safer alternatives are, in order: remove protocol pins, upgrade the peer to TLS 1.2+, and only if unavoidable, a per-JVM override file with a removal date.
Verify the fix
// TlsCheck.java — run with: java TlsCheck.java example.com (JDK 11+)
import javax.net.ssl.*;
public class TlsCheck {
public static void main(String[] args) throws Exception {
SSLSocketFactory f = SSLContext.getDefault().getSocketFactory();
try (SSLSocket s = (SSLSocket) f.createSocket(args[0], 443)) {
SSLParameters p = s.getSSLParameters();
p.setEndpointIdentificationAlgorithm("HTTPS"); // keep hostname verification on
s.setSSLParameters(p);
s.startHandshake();
System.out.println(s.getSession().getProtocol() + " " + s.getSession().getCipherSuite());
}
}
}
Run it with the same JDK and JVM options as your application. It should print TLSv1.3 or TLSv1.2 and a cipher suite. openssl s_client -connect example.com:443 -servername example.com -tls1_2 confirms from outside Java that the server accepts TLS 1.2. The SSL checker shows which versions a public server supports; the TLS config generator gives a modern server configuration if you own the other side. If the handshake now gets further but fails on certificates, continue with PKIX path building failed.
FAQ
Does this error mean the server is too old?
Not directly. Java raises it before contacting the server, because its own list of enabled protocols and cipher suites is empty after the security policy is applied. The usual reason is that someone pinned TLSv1 in code or configuration years ago, often to talk to an old server. If you enable TLS 1.2 and the server still cannot do it, you will then get a protocol_version alert or the client preferences error instead.
Which JDK versions disabled TLS 1.0 and 1.1?
Oracle's release notes list the change in JDK 8u291 (released April 20, 2021) and 11.0.11, and the OpenJDK change JDK-8202343 shipped in JDK 16. The protocols were added to jdk.tls.disabledAlgorithms in java.security; RFC 8996 formally deprecated them the same year.
Can I re-enable TLS 1.0 for one legacy system?
As a last resort, yes, for one JVM only: start it with -Djava.security.properties=/path/legacy-tls.security containing a copy of jdk.tls.disabledAlgorithms without TLSv1. That file appends to and overrides the master java.security only for that process. Plan to remove it; TLS 1.0 is deprecated by RFC 8996.
How do I see which protocols and cipher suites the JVM is ignoring?
Run with -Djavax.net.debug=ssl:handshake. The JSSE debug log prints lines such as Ignore unsupported cipher suite: ... for TLSv1.2 and No available cipher suite for TLSv1.3, which show exactly why each protocol was dropped.