
Running ss -ant on a Linux server may reveal hundreds or thousands of connections in the ESTABLISHED state. That number can look alarming, but it does not prove that the server is overloaded or leaking sockets. ESTABLISHED only means that the TCP handshake completed and the endpoints still consider the connection open. It does not tell you whether useful application data is moving at this moment.
WebSocket services, HTTP/2 applications, database pools, message consumers, reverse proxies, and RPC clients can legitimately keep connections open for a long time. The useful questions are therefore more specific: Which process owns the sockets? Which local port and remote addresses dominate? Are the connections transferring data or remaining idle? Is the count stable with traffic, or does it grow without returning to its normal baseline?
When a Large ESTABLISHED Count Can Be Normal
Long-lived established connections are expected in several common architectures:
WebSocket applications, real-time notifications, chat systems, and long polling;
HTTP keep-alive and HTTP/2 sessions between clients, proxies, and application servers;
database, Redis, and message-queue connection pools;
persistent RPC channels between microservices;
large downloads, uploads, or media transfers;
reverse proxies maintaining reusable upstream connections.
If the count rises and falls with active users or request volume, while latency, errors, memory, file descriptors, and network throughput remain healthy, the sockets may simply represent normal capacity. A stronger warning sign is a connection count that keeps increasing after traffic has fallen, especially when one process approaches its open-file limit.
Start with the Connection Count and Its Trend
Use the following commands for a quick system-wide view:
ss -s cat /proc/net/sockstat ss -ant state established
Do not base a diagnosis on a single snapshot. Sample the count over time and compare it with requests per second, active sessions, CPU, memory, network throughput, application latency, and error rates. A stable ratio between connections and real workload usually tells a different story from unbounded socket growth with flat traffic.
Find the Ports, Peers, and Processes Responsible
Group Connections by Local Port
ss -ant state established | awk 'NR>1 {split($4,a,":"); print a[length(a)]}' | sort | uniq -c | sort -nr | headThis identifies whether the sockets mainly belong to a web listener, database endpoint, or internal service. Because IPv6 addresses contain multiple colons, use a more robust parser or structured monitoring in production if the simple pipeline does not match your output format.
Group Connections by Remote Address
ss -ant state established | awk 'NR>1 {print $5}' | sed 's/:[^:]*$//' | sort | uniq -c | sort -nr | headA concentration behind one source address does not automatically mean one client. Load balancers, forward proxies, carrier NAT, and corporate gateways can make many users appear behind the same address. Interpret the result together with the actual network path and forwarded client-address headers.
Map Sockets to Processes
sudo ss -antp state established sudo lsof -nP -iTCP -sTCP:ESTABLISHED
Record the PID, process name, local port, and remote endpoint. If one service shows continuous growth, examine its connection pool, worker model, exception handling, timeout paths, and socket cleanup logic.
Tell Active, Idle, and Backed-Up Connections Apart
The TCP state alone does not show application activity. Ask ss for internal details:
sudo ss -iantop state established
Inspect send and receive queues, retransmissions, RTT, congestion data, and socket timers. A persistently large Send-Q can indicate a slow-reading peer, congestion, or an application on the other side that cannot keep up. A large Recv-Q can indicate that the local application is not reading data already delivered by the kernel.
When packet-level evidence is necessary, capture a narrow scope for a short period:
sudo tcpdump -ni any tcp port 443
Packet captures can contain sensitive information and can add overhead. Limit the interface, hosts, ports, and duration, then store and review the capture according to your security policy.
Check File Descriptor Headroom
Each socket normally consumes a file descriptor. Compare current use with the process and system limits:
ulimit -n cat /proc/<PID>/limits ls /proc/<PID>/fd | wc -l cat /proc/sys/fs/file-nr
When a process approaches Max open files, new sockets, logs, and ordinary file operations may fail. Raising the limit can provide capacity, but it does not fix an application that never releases connections. Confirm the growth pattern, memory budget, and service-manager limits before changing the ceiling.
Why TCP Keepalive Does Not Remove Every Idle Connection
Linux exposes three commonly reviewed TCP keepalive settings:
sysctl net.ipv4.tcp_keepalive_time sysctl net.ipv4.tcp_keepalive_intvl sysctl net.ipv4.tcp_keepalive_probes
tcp_keepalive_timecontrols how long an eligible socket remains idle before probes begin;tcp_keepalive_intvlcontrols the interval between probes;tcp_keepalive_probescontrols how many unsuccessful probes are sent before the peer is considered unreachable.
These kernel defaults only affect sockets for which the application has enabled SO_KEEPALIVE. Changing sysctl values does not automatically activate keepalive on every established connection.
Application heartbeats and TCP keepalive also solve different problems. An application heartbeat can prove that the protocol handler and business session are still responsive. TCP keepalive mainly helps detect a failed peer or broken network path. WebSocket libraries, database drivers, and RPC frameworks may therefore need their own ping, heartbeat, or idle-timeout configuration.
Common Root Causes and the Right Response
Legitimate Long-Lived Connections Exceed Capacity
If sockets correlate with active clients, treat the issue as capacity planning. Check process file descriptors, per-connection memory, load-balancer limits, worker distribution, and pool sizing. Scale out or partition the workload when required.
Application Connection Leak
Review success, error, timeout, cancellation, and retry paths to ensure every connection is returned to its pool or closed. HTTP and database pools need sensible maximum size, maximum idle count, idle expiration, and connection lifetime. The durable fix belongs in application or pool behavior rather than a system-wide forced cleanup.
Slow Clients or Poor Network Conditions
Use queue sizes, retransmissions, response time, and application logs to confirm the pattern. Read and write timeouts, body-size limits, and concurrency controls may help, but setting aggressive values merely to reduce the connection count can disconnect valid large transfers and users on slower networks.
Mismatched Idle Timeouts Across the Path
Load balancers, NAT gateways, firewalls, proxies, and applications may all use different idle timeouts. An application heartbeat is usually configured shorter than the shortest relevant network idle timeout, with a safety margin. Select the actual value from current device documentation, application behavior, and controlled testing.
Connection Tracking Pressure
On a host or gateway using Netfilter connection tracking, also inspect:
sudo conntrack -S sysctl net.netfilter.nf_conntrack_count sysctl net.netfilter.nf_conntrack_max
The command may be unavailable if the tool is not installed or the host does not use that network role. The conntrack table and application socket table are related but separate layers, so investigate them with the network topology in mind.
A Practical Troubleshooting Order
Measure the connection count, growth rate, and start time.
Compare the trend with traffic, active users, latency, errors, and throughput.
Group sockets by local port and remote address.
Map the dominant sockets to PIDs and services.
Review send queues, receive queues, retransmissions, and timers.
Check process file descriptors and pool limits.
Verify application timeouts, heartbeats,
SO_KEEPALIVE, and kernel defaults.Compare load-balancer, NAT, firewall, and proxy idle timeouts.
Use a controlled packet capture or application trace only when needed.
Change Settings Safely
Do not roll out keepalive, pool, or timeout changes to every server at once. Save the existing values and a monitoring baseline, apply the change to a small group, and watch connection count, reconnect rate, errors, P95/P99 latency, CPU, memory, and file descriptors. Keep tested rollback values and verify that persistent configuration survives a restart.
If a shorter idle timeout reduces the socket count but causes reconnect storms, dropped sessions, or database churn, the pressure has probably moved from idle connections to handshakes and connection creation rather than being eliminated.
Verify the Fix
The established count should track real workload and stop growing without a bound.
File descriptor use should return to a safe operating range.
Pool wait time, timeouts, and rejected connection counts should improve.
Reconnects, handshakes, and application errors should not spike.
Slow-network clients, long jobs, uploads, and downloads should still work.
The intended settings should remain active after a restart or rolling deployment.
Frequently Asked Questions
Does a high ESTABLISHED count mean the server is under attack?
No. Normal long-lived sessions and high concurrency can create the same TCP state. Confirm source distribution, request behavior, bandwidth, authentication logs, error rates, and the normal business baseline before classifying it as an attack.
Can I simply kill the connections?
Mass disconnection is not a routine fix. It interrupts legitimate users and can trigger a synchronized reconnect wave. Identify the service, connection type, and root cause first. Even emergency action should limit the scope and include rollback and recovery planning.
Should I set tcp_keepalive_time to a very small value?
An overly aggressive value increases probe traffic and the risk of unwanted disconnects. It also has no intended effect on sockets where the application did not enable SO_KEEPALIVE. Test changes against the business idle cycle and intermediate network timeouts.
Why do the connections return immediately after a service restart?
Legitimate clients and automatic reconnect logic will rebuild their sessions. A restart only clears current state; it does not correct capacity limits, leaks, timeout mismatches, or client behavior.
Conclusion
When a Linux server has many ESTABLISHED connections, start by connecting the socket count to ports, peers, processes, workload, queue behavior, and file descriptor use. Plan capacity when the sessions are legitimate. When they are idle, leaked, or affected by mismatched timeouts, correct the appropriate application, pool, keepalive, or network-device setting. System-wide changes should always include a baseline, staged rollout, monitoring, and a tested rollback.
References
RFC 9293: Transmission Control Protocol (TCP). Reviewed September 4, 2026.
Linux Kernel Documentation: IP Sysctl. Reviewed September 4, 2026.
Linux man-pages: ss(8). Reviewed September 4, 2026.
Linux man-pages: tcp(7). Reviewed September 4, 2026.