Marcio Cunha

How to increase simultaneous connection limits on Linux

Learn how to fix file descriptor exhaustion errors on Linux servers under high load by adjusting ulimit, systemd, and kernel parameters.

Marcio Cunha•6 min
Also available in:PortuguêsEspañol
Summary
  • File descriptor exhaustion happens when a process hits the maximum allowed open files limit.
  • The ulimit utility controls resource limits for user sessions but only applies temporarily.
  • Services managed by systemd ignore traditional configuration files and need explicit directives.
  • Kernel adjustments via sysctl ensure the operating system supports massive socket pools.
  • Monitoring descriptor usage prevents sudden web server crashes in high-traffic environments.

What happens when Linux runs out of simultaneous connections

When a high-performance web server starts receiving thousands of simultaneous requests, it eventually hits an invisible barrier imposed by the operating system. This limit often results in the dreaded 'Too many open files' error, which can crash entire applications. In practice, this means the operating system has reached the maximum number of file descriptors allowed for a specific process or user. Since Linux treats everything as a file — including network connections, TCP sockets, and pipes — opening a new browser tab or receiving an HTTP request consumes precious descriptors from this internal table.

For system administrators managing servers under heavy loads, understanding how to manage these resources is just as crucial as learning how to clean the systemd journal cache and free up disk space on Linux to prevent storage bottlenecks. Without proper configuration, even a machine with dozens of gigabytes of RAM and robust processors will refuse new network connections simply because internal kernel bureaucracy prevents the opening of new descriptors. Solving this issue requires tweaking three distinct layers: the resource control command per session, the service configurations, and the global operating system parameters.

How the ulimit command and its limits work

The ulimit command is the traditional Linux tool to inspect and set resource limits for processes started in the terminal. It handles two fundamental concepts: the soft limit, which acts as a warning or flexible ceiling that a process can try to exceed, and the hard limit, representing the absolute ceiling imposed by the administrator that can never be exceeded without elevated privileges.

To check the current limits of your active session, simply run a quick command in the terminal. In practice, this reveals the descriptor ceiling that your user can open simultaneously. Check out this practical query example:

ulimit -n

The output displays an integer, such as 1024, representing the maximum number of files and network connections your user can manage at once. If your web application exceeds this number of connected clients, new connections will be summarily rejected, causing failures for end-users. However, changing the value with ulimit -n 65535 only temporarily resolves the issue for that specific interactive session, disappearing as soon as you close the terminal window or restart the login session.

How to set permanent limits in limits.conf

To ensure that servers and applications always start with their limits properly adjusted for good, you need to configure the operating system's security files. The main file for this purpose is located within the security configuration directory of PAM, the Linux authentication subsystem. Here, we can define specific rules for regular users or the entire system.

Open the configuration file with a text editor using superuser privileges and add the necessary directives to raise the open files ceiling. In practice, you define both the soft and hard limits for the user running the application, such as the user running the Nginx or Apache web server. See how to structure the modification:

*               soft    nofile  65535
*               hard    nofile  65535
www-data        soft    nofile  100000
www-data        hard    nofile  100000

This adjustment ensures that any regular user gets a limit of 65,535 descriptors, while the specific www-data user receives an even higher ceiling of 100,000 simultaneous connections. However, note that in modern Linux distributions using systemd as the init manager, these traditional rules might be ignored by services running as isolated daemons, requiring an extra configuration step directly inside the systemd service units.

How to configure systemd to bypass default ulimits

Systemd revolutionized Linux initialization, but it also introduced new layers of isolation that frequently catch administrators by surprise. Modern services managed by systemd run in their own namespaces and completely ignore the limits configured in the limits.conf file. If you increased the limit in the previous file and noticed that your web service still crashes with the same exhausted descriptor error, the culprit is almost certainly systemd's resource isolation.

To fix this unwanted behavior for a specific service, such as Nginx or a Node.js process, you need to create an override file. This mechanism lets you alter directives without modifying the original file supplied by the system package. Here is how to open the configuration editor for your service:

sudo systemctl edit nginx

Inside the editor that opens, you must insert the directive responsible for forcing the new file descriptor ceiling directly upon startup for that specific service. In practice, this tells the system manager to open the resource valve for the process in question. Add the following text block:

[Service]
LimitNOFILE=100000
LimitNOFILE=100000:100000

After saving the file, you need to reload the manager configurations and restart the service for the change to take effect immediately. To validate whether the modification worked, you can inspect the active process limits at runtime using systemd's inspection tools. This verification ensures your application won't fail again under sudden spikes in network traffic.

How to adjust global kernel parameters with sysctl

Beyond tweaking limits per user and per service, the Linux kernel itself has global locks controlling the total amount of open files across the entire operating system. If the sum of descriptors from all active processes reaches this global ceiling, no new application will be able to open files or sockets, regardless of individual limits configured previously.

To view the current global system limit, you can check the kernel's virtual directory tree through a simple terminal command. In practice, this number represents the health of the entire I/O ecosystem of the operating system. Here is how to perform the check:

cat /proc/sys/fs/file-max

If this value seems low for your hardware capacity — for example, on corporate servers with hundreds of gigabytes of RAM —, it must be permanently increased in the kernel parameters configuration file. Open the sysctl configuration file for editing with the appropriate command and add the new global directive:

sudo nano /etc/sysctl.conf

Add the following line at the end of the document to elevate the global file system ceiling to a safe high-load tier:

fs.file-max = 2097152

To apply the change immediately without rebooting the entire machine, run the command that reloads kernel settings. This practice ensures that the operating system accepts new simultaneous connection pools stably and without interruptions to production services. To complement this implementation in production environments, see our related technical analyses on How to test the motherboard Super I/O chip with multimeter and How to configure port VLAN on a TP-Link managed switch.

sudo sysctl -p

Final Considerations

Managing simultaneous connections on Linux servers requires a holistic view ranging from individual process behavior to restrictions imposed by the operating system core. File descriptor exhaustion is one of the most common issues in high-load environments, but it can be completely avoided with proper planning across ulimit, systemd, and global kernel parameter configuration layers.

Adopting a monitoring routine for these limits ensures your infrastructure remains resilient even under unexpected traffic spikes or mass access campaigns. Keeping these adjustments documented and tested in staging environments prevents unpleasant surprises and ensures your web services deliver the maximum availability and performance expected by users.