The remote side, or a firewall, proxy or load balancer in between, aborted the connection with a TCP RST.
Common causes: idle connections killed by a timeout, the server crashing or restarting, the server rejecting the request (TLS version, size limits), or reusing a pooled connection the server already closed.
Your code isn't necessarily wrong: look at the other side's logs first.
Fixes: retry idempotent requests, validate pooled connections, keep pool idle timeouts shorter than the server's or load balancer's, and match TLS settings.
✦ Definition~90s read
What is java.net.SocketException?
java.net.SocketException: Connection reset is thrown when Java reads from or writes to a TCP connection that the other side (or something in between) has abruptly aborted by sending a TCP RST packet.
★
You're on a phone call and the other person doesn't say goodbye: the line just goes dead mid-sentence.
Plain-English First
You're on a phone call and the other person doesn't say goodbye: the line just goes dead mid-sentence. A normal hang-up is a polite "bye" (TCP FIN). A connection reset is the line being cut (TCP RST), and Java tells you the next time you try to talk or listen.
Connection reset is one of the most common Java networking errors: you'll see it in HTTP clients, JDBC drivers, message brokers, and game clients (Minecraft shows it as Internal Exception: java.net.SocketException: Connection reset). The message comes from the operating system's TCP stack, so the cause is rarely in the line of Java code that throws it. This guide explains what a reset is, reproduces one in a few lines, and walks through the causes in order of how often they happen.
FIN vs RST: Why 'Reset' Is Different
TCP has two ways to end a connection. A FIN is a polite close: the other side finishes sending, and your read returns -1 (end of stream). A RST is an abort: the connection is torn down immediately, and the next read or write on your side throws SocketException: Connection reset.
Something sends RST when it receives data for a connection it no longer knows about, when an application closes a socket with linger set to 0, or when a firewall or proxy decides to kill the connection.
🔥Related messages
Connection reset by peer and Broken pipe are close cousins: they usually appear on writes rather than reads, for the same underlying reason.
🎯 Key Takeaway
A reset is an abrupt abort, not a normal close.
Reproduce It in 20 Lines
This program starts a tiny server that accepts a connection and aborts it with a RST (linger 0), then reads from the client side. It produces exactly the exception you see in production.
ResetDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
publicclassResetDemo {
publicstaticvoidmain(String[] args) throwsException {
try (ServerSocket server = newServerSocket(0)) {
int port = server.getLocalPort();
// The "server" accepts, then aborts the connection instead of closing it politely.Thread t = newThread(() -> {
try (Socket s = server.accept()) {
s.setSoLinger(true, 0); // linger 0 = send TCP RST on close, not FIN
} catch (Exception ignored) { }
});
t.start();
try (Socket client = newSocket("localhost", port)) {
t.join(); // wait until the server has reset usInputStream in = client.getInputStream();
in.read(); // reading from a reset connection
} catch (java.net.SocketException e) {
System.out.println("Caught: " + e);
}
}
}
}
A reproduction like this is useful for checking your retry and error-handling logic in tests.
🎯 Key Takeaway
A RST from the other side turns your next read into Connection reset.
The Common Causes
Idle connections killed in the middle: load balancers, NAT gateways and firewalls drop idle connections; reusing one from a pool triggers a reset.
The server closed or crashed: a restart, an out-of-memory kill, or a deliberate abort.
The server rejected the request: an unsupported TLS version or cipher, a request or header over a size limit, or plain HTTP sent to an HTTPS port.
Too many connections: the server's backlog or connection limit is full.
Network or security software: VPNs, antivirus, or a router dropping the connection (common for desktop and game clients).
⚠ Not always your bug
The line that throws is just where Java noticed. The cause is usually on the other side, so check the server, proxy and load balancer logs for the same timestamp.
🎯 Key Takeaway
Idle timeouts in the middle are the most common cause in services.
Fixes That Work
Match timeouts: keep your connection pool's idle/keep-alive timeout below the shortest idle timeout on the path. Validate connections: most pools (HikariCP for JDBC, Apache HttpClient, OkHttp) can test or evict idle connections. Retry safely: retry idempotent requests (GET, PUT with the same body) once or twice with backoff; don't blindly retry payments or other non-idempotent calls. Match TLS: if a handshake is reset, check both sides support a common TLS version.
RetryOnReset.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.net.SocketException;
import java.util.concurrent.Callable;
publicfinalclassRetryOnReset {
// Retry an idempotent call a few times when the connection is reset.publicstatic <T> T call(Callable<T> op, int attempts) throwsException {
for (int i = 1; ; i++) {
try {
return op.call();
} catch (SocketException e) {
if (i >= attempts) throw e;
Thread.sleep(200L * i); // simple linear backoff
}
}
}
}
🎯 Key Takeaway
Shorter client idle timeouts plus safe retries remove most resets.
● Production incidentPOST-MORTEMseverity: high
The First Request After Lunch Always Failed
Symptom
Intermittent java.net.SocketException: Connection reset on the first requests after idle periods; retries succeeded.
Assumption
The team assumed the partner's API was unstable.
Root cause
A load balancer between the services silently dropped connections idle for longer than its timeout. The client's pool kept those connections and reused them; the first write on a dead connection got a RST.
Fix
Set the pool's idle timeout below the load balancer's, enabled validation of idle connections, and added a single retry for idempotent requests.
Key lesson
A reset often comes from something in the middle, not the server.
Pool idle timeouts must be shorter than every timeout along the path.
Retry only idempotent operations automatically.
Production debug guideWork out who sent the RST and why4 entries
Symptom · 01
Happens after idle periods
→
Fix
Compare pool idle timeouts with server, proxy and load balancer idle timeouts; make the client's shorter.
Symptom · 02
Happens on every request to one server
→
Fix
Check that server's logs: it may be rejecting the request (TLS version, size limit, auth) and closing abruptly.
Symptom · 03
Coincides with deployments
→
Fix
The server is restarting; add retries with backoff and graceful shutdown on the server.
Symptom · 04
Game or app client (e.g. Minecraft)
→
Fix
Usually the server closed the connection or the network dropped; check server status, firewall/antivirus and router, then reconnect.
⚙ Quick Reference
2 commands from this guide
File
Command / Code
Purpose
ResetDemo.java
public class ResetDemo {
Reproduce It in 20 Lines
RetryOnReset.java
public final class RetryOnReset {
Fixes That Work
Key takeaways
1
Connection reset means the TCP connection was aborted with a RST.
2
The cause is usually the other side or a device in between.
3
Idle-connection timeouts in load balancers are the top cause in services.
4
Validate pooled connections and retry only idempotent calls.
Common mistakes to avoid
3 patterns
×
Retrying every request on reset
Symptom
Duplicate orders or payments after a network blip.
Fix
Only auto-retry idempotent operations; use idempotency keys for the rest.
×
Raising timeouts on the client only
Symptom
Resets continue because the load balancer still drops idle connections.
Fix
Make the client's idle timeout shorter than every timeout in the path.
×
Treating it as a Java bug
Symptom
Hours spent in client code.
Fix
Check the other side's logs and network devices at the same timestamp.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
Q01SENIOR
What's the difference between a read returning -1 and SocketException: C...
Q02SENIOR
Why do pooled HTTP connections sometimes fail with Connection reset afte...
Q01 of 02SENIOR
What's the difference between a read returning -1 and SocketException: Connection reset?
ANSWER
-1 means the peer closed gracefully with a FIN after sending everything. Connection reset means the connection was aborted with a RST, so pending data may be lost and the next read or write fails.
Q02 of 02SENIOR
Why do pooled HTTP connections sometimes fail with Connection reset after idle periods?
ANSWER
A load balancer, NAT or the server closed the idle connection, but the client pool still holds it. The next write gets a RST. Fix by evicting or validating idle connections with a timeout shorter than the infrastructure's.
01
What's the difference between a read returning -1 and SocketException: Connection reset?
SENIOR
02
Why do pooled HTTP connections sometimes fail with Connection reset after idle periods?
SENIOR
FAQ · 3 QUESTIONS
Frequently Asked Questions
01
What does java.net.SocketException: Connection reset mean?
The other end of the TCP connection, or something in between, aborted the connection with a reset (RST) packet, and Java noticed on the next read or write.
Was this helpful?
02
How do I fix Internal Exception: java.net.SocketException: Connection reset in Minecraft?
It means the server or network dropped the connection. Check the server is up, restart your router, allow Java through your firewall or antivirus, try without a VPN, then reconnect.
Was this helpful?
03
Is Connection reset the same as Connection refused?
No. Refused means nothing was listening when you tried to connect. Reset means a connection existed and was then aborted.