What limits concurrent connections on Linux?
Check process descriptors, application pools, listen queues, source ports, and memory before raising limits.
There is no single Linux setting for maximum connections. The effective limit comes from the application, its processes, the network path, and the resources each connection uses. First distinguish established connections from new-connection bursts and outbound connection creation.
Inspect the running process's descriptor limits
A socket held open by an application normally occupies a file descriptor, alongside files, pipes, and other descriptors:
ulimit -n
cat /proc/1234/limits
cat /proc/sys/fs/file-max
cat /proc/sys/fs/file-nr
Replace 1234 with the service PID. ulimit reports the current shell's limit, which may differ from the running service's. A temporary shell change does not update an existing process.
PAM login limits and systemd service limits also differ. For a systemd-managed service, inspect LimitNOFILE and use an appropriate unit override when a measured descriptor limit needs to change. Reload the unit definitions and restart the affected process under the new limit; daemon-reload alone does not change a running process's limits. Verify the result in /proc/<pid>/limits.
Distinguish queues from established-connection capacity
Read the relevant kernel values with sysctl:
sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
sysctl net.core.netdev_max_backlog
sysctl net.ipv4.ip_local_port_range
The accept backlog, incomplete-handshake backlog, and network input backlog serve different stages. Increasing one does not create a universal capacity increase. Compare drops, retransmissions, and application accept behavior with the observed workload before tuning.
Outbound connections can exhaust the available source-address/source-port combinations for a destination, particularly with heavy churn or NAT. Established TCP connections are distinguished by their endpoint tuple; a listening server is not limited to 65,535 clients simply because its listening port is a 16-bit value.
Avoid changing tcp_tw_reuse blindly. Its meaning and defaults are kernel-dependent, and reuse must preserve TCP correctness. Connection pooling, keep-alive, and reducing needless churn are often the first application-level checks.
Account for the server and upstream connections
Nginx's worker_connections counts connections handled by each worker, including upstream connections. A proxied request can consume both client and upstream sockets, plus other descriptors. Multiplying workers by worker_connections is therefore not a direct estimate of supported users.
Apache capacity depends on its MPM and worker limits. PHP-FPM pools, database pools, application queues, and downstream APIs impose their own bounds. An event-driven Node.js process is not limited to one connection simply because JavaScript execution is typically on one thread.
Measure resource and path limits
Memory usage depends on socket buffers, TLS state, protocol, and application data. CPU, scheduling, bandwidth, connection tracking, load balancers, and NAT devices can impose earlier limits. There is no reliable universal memory figure for 100,000 connections.
Start with ss -s, application pool metrics, process descriptor usage, and the original error. Check the component returning the failure, then work outward through server limits and infrastructure. Test a justified change under representative load and keep rollback values. A larger limit can simply move the failure to memory exhaustion or an overloaded database.
References: Nginx worker_connections, systemd resource limits, and Linux IP sysctls.
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan