The NAT Gateway drops idle connections after 350 seconds and sends a RST
It is not a silent timeout. The connection is actively reset, which means your application sees a connection error at a moment when nothing was wrong, and connection pools are the most common casualty.
· Venerable Networks
A NAT Gateway drops a connection that has been idle for 350 seconds. That number is widely known. The part that matters operationally is what happens next.
Per the NAT Gateway troubleshooting documentation, when a connection exceeds the idle timeout the NAT Gateway sends an RST to whichever side attempts to continue the connection. It is not a black hole. The connection is actively reset.
That distinction changes the symptom completely, and it changes the fix.
What it looks like in an application
A connection pool opens connections to an external service. Traffic is bursty — busy during business hours, quiet overnight, or busy in a batch window and quiet between. Connections sit idle in the pool.
At some point one is reused. The NAT Gateway has long since forgotten it, so the first packet on that connection gets an RST, and the application logs a connection reset at a moment when the network is entirely healthy and nothing changed.
The failures cluster around the start of activity after a quiet period, which is the fingerprint. First request after idle fails, retry succeeds, everything is fine for an hour, quiet period, first request fails again.
If it were a silent timeout you would see a hang and then a timeout error, which people correctly attribute to the network. Because it is an RST, applications and libraries report it as the peer closing the connection — so the investigation starts at the remote service, which is the wrong end.
Why 350 seconds is an awkward number
It is shorter than most default TCP keepalive intervals. Linux defaults tcp_keepalive_time to 7200 seconds — two hours — so a connection relying on OS keepalives to stay warm through a NAT Gateway will be reset roughly twenty times before the first keepalive fires.
That is the whole problem in one comparison. The defaults on both sides are individually reasonable and jointly broken.
The fixes, in order of preference
Send keepalives more often than 350 seconds. The documented recommendation, and the right answer. Set the interval below the idle timeout with margin — 240 seconds is a common choice. Do it in the application if you can, because that is where the connection is owned:
# Python, on the socket
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 240)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 60)Or system-wide, if the application does not expose it:
sysctl -w net.ipv4.tcp_keepalive_time=240
sysctl -w net.ipv4.tcp_keepalive_intvl=60
sysctl -w net.ipv4.tcp_keepalive_probes=5Set the pool's own idle eviction below 350 seconds. Most connection pools can close connections after an idle period. Evicting at 300 seconds means the pool never hands out a connection the NAT Gateway has dropped. This is often easier to ship than socket options and it is equally effective.
Retry on reset, deliberately. Necessary regardless, because a reset can happen for other reasons, but it should not be the only measure. A retry that succeeds hides the problem, and a hidden problem plus a non-idempotent endpoint eventually produces a duplicate.
Do not route the traffic through the NAT Gateway at all where that is an option. Traffic to AWS services can use gateway or interface endpoints and stops being subject to this entirely.
The timeout is not configurable
There is no setting. 350 seconds is fixed, which means every design decision here belongs on your side of the connection.
Worth noting that other AWS components in the same path have their own idle timeouts with different values — a Network Load Balancer has its own, and an Application Load Balancer's is configurable. If traffic traverses several of them, the effective timeout is the shortest one, and the RST comes from whichever gave up first. When you are debugging a reset, enumerate every device in the path and take the minimum rather than assuming the one you are thinking about is the binding constraint.
Telling it apart from port exhaustion
Both are NAT Gateway problems and they present differently:
Idle timeout. Failures correlate with connection age and cluster after quiet periods. ErrorPortAllocation is zero. Connection counts are unremarkable.
Port exhaustion. Failures correlate with connection volume toward one destination. ErrorPortAllocation is non-zero. The relevant limit is 55,000 simultaneous connections per unique destination — destination IP, port, and protocol — not per gateway, which changes both the diagnosis and the remedy.
The remedies differ too. For idle timeout you change connection behaviour. For port exhaustion the lever is more IPv4 addresses on the same NAT Gateway, up to eight, not more NAT Gateways — each address gets its own per-destination budget.
Watching ErrorPortAllocation is what separates them, and it is worth an alarm regardless. A gateway can sit at a modest total connection count and still throw allocation errors, because the exhausted resource is ports toward one destination.
The NAT Gateway guide covers both failure modes and the port accounting behind them. For the NACL interaction that produces a third, intermittent flavour of NAT Gateway failure, there is a lab: the egress that worked half the time.