Error message
javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
Also printed as
- Remote host terminated the handshake
JDK 21 and 25 print "Remote host terminated the handshake". Logs from Java 8 commonly show the same situation as "Remote host closed connection during handshake" caused by "SSL peer shut down incorrectly".
Java (JSSE) — the TCP connection closed during the handshake without a TLS alert
What it means
The other end (or something in between) closed the TCP connection while the JVM was in the TLS handshake, without sending a TLS alert. Java cannot know the reason; it only sees the connection end. Typically a firewall, proxy or load balancer drops the handshake, or the server rejects the ClientHello silently.
Why it happens
A proxy or firewall in the path
commonNetworks that require an HTTPS proxy, deep-packet-inspection firewalls that block by SNI or JA3/JA4 fingerprint, and VPNs often end blocked connections silently.
The server closes handshakes it rejects
commonSome servers and load balancers close the connection instead of answering with an alert when the protocol version, cipher list or SNI is unacceptable.
SNI missing
occasionalConnecting by IP address, or with jsse.enableSNIExtension=false, sends no server name; CDN edges commonly drop such handshakes.
Connection limits and rate limiting
occasionalServers at their connection limit, or rate limiters under burst traffic, reset new connections; the error then appears intermittently.
How to fix it
- 1.
Trace the handshake and compare with openssl
javax.net.debug shows how far the handshake got; if openssl s_client from the same host is cut off too, the cause is the network or server, not the JVM.
bash java -Djavax.net.debug=ssl:handshake -jar app.jar 2>&1 | grep -E 'ClientHello|server_name|EOF|terminated' # Same handshake without Java: is it the network or the JVM? openssl s_client -connect api.example.com:443 -servername api.example.com -brief </dev/null - 2.
Use the network's proxy
Java does not use the OS or browser proxy settings by default; set https.proxyHost/https.proxyPort (or -Djava.net.useSystemProxies=true) and exclude internal hosts with http.nonProxyHosts.
bash # Corporate networks: route HTTPS through the proxy the browser uses java -Dhttps.proxyHost=proxy.example.net -Dhttps.proxyPort=3128 \ -Dhttp.nonProxyHosts="localhost|*.internal.example.com" -jar app.jar - 3.
Send SNI
Use the host name in the URL and keep the SNI extension enabled.
text Connect with the host name (not an IP address) so JSSE sends SNI, and do not set -Djsse.enableSNIExtension=false: front ends that need SNI close such connections.