October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
VGSources
Blog

How to Handle 50,000 Concurrent Connections on a Server

Learn how to design, tune and test a Linux NGINX server for 50,000 concurrent connections without confusing connection count with real capacity.
Length11 min Posted Quest giverVGSources Team
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To handle 50,000 concurrent connections, use an event-driven server such as NGINX on Linux, raise both its connection and file-descriptor ceilings, size the listener backlog for bursts, and test the exact protocol and traffic pattern you expect. There is no universal CPU or RAM specification: 50,000 mostly idle WebSockets, 50,000 active HTTPS clients, and 50,000 reverse-proxied game sessions impose very different costs.

Start by defining what “50,000 connections” means

“Concurrent” means open at the same time; it does not say how much work those connections generate. A game gateway carrying 50,000 quiet WebSockets can be limited mainly by socket and memory overhead. The same number of clients sending frequent messages, negotiating TLS, or being proxied to separate game services also consumes CPU, bandwidth, upstream sockets and application capacity.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Workload characteristic Why it changes the design
Protocol HTTP keep-alive, WebSocket, raw TCP and other protocols have different parsing, timeout and buffering behavior.
Connection lifetime Long-lived sessions keep descriptors allocated; short-lived sessions create more accepts, closes and handshakes.
Traffic rate Mostly idle sockets stress concurrency limits, while frequent messages stress CPU, application queues and network throughput.
TLS Encryption consumes CPU, especially during new handshakes. Reusing established sessions is a different workload from constant reconnects.
Proxying A reverse proxy generally needs a client socket and an upstream socket for one flow, so the descriptor budget is larger than the client count.
Payload and buffering Large messages or response buffers increase memory pressure even when the socket count is unchanged.

Treat 50,000 as a measured workload target rather than proof that any particular machine can sustain it. Capacity is established by a representative load test on the chosen hardware, operating-system kernel, NGINX version, configuration and application.

Use an event-driven Linux architecture

Why epoll is the usual foundation

NGINX documents epoll as an efficient connection-processing method on Linux 2.6 and later. Event-driven I/O lets a small number of worker processes monitor many sockets without dedicating one blocked thread to every connection. That is the appropriate model for many mostly idle HTTP or WebSocket sessions.

Choose the event method supported by the operating system and verify the active configuration rather than assuming that a high connection number alone solves scaling. The event loop only makes socket readiness efficient; your game logic, message handling, TLS, storage and upstream services can still become bottlenecks.

Distribute sockets among workers

NGINX runs one or more worker processes. worker_connections is a per-worker ceiling and counts proxied connections as well as client connections. The documented default is 512, which is a starting default, not a 50,000-connection capacity recommendation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The rough aggregate ceiling is the sum of the workers’ configured connection limits, but the practical ceiling is the lowest of several limits: available workers, open-file limits, memory, CPU, network capacity and the application’s own limits. A configuration that mathematically totals 50,000 can still fail if one worker reaches its descriptor limit or if upstream sockets double the required descriptors.

Budget file descriptors before tuning connection counts

Why the open-file limit stops designs early

Each socket consumes an open file descriptor. NGINX states that the number of simultaneous connections cannot exceed the current maximum-open-files limit. A reverse-proxy flow commonly uses one descriptor for the client and another for the upstream, so 50,000 client connections can require close to 100,000 socket descriptors before accounting for listening sockets, logs, cache files and other open files.

That two-descriptor figure is a planning model, not a universal constant: direct connections, connection reuse, protocol upgrades and failures can change the exact count. Measure the running process and leave headroom for bursts and non-socket files.

Layer What to inspect Failure symptom
NGINX worker worker_connections and worker_rlimit_nofile Workers refuse new connections even though system resources remain.
Service manager For systemd, the unit’s LimitNOFILE Shell limits look high, but the daemon inherits a lower limit.
Process limit The effective soft and hard open-file limits of the running worker Configuration appears correct but the process still reaches “too many open files.”
Kernel-wide limits System-wide file-handle ceilings and current usage Several services together exhaust the host’s file handles.

Apply limits consistently

Set the service manager’s limit high enough for the intended total, then use NGINX’s worker_rlimit_nofile where appropriate and set worker_connections below the descriptor budget for each worker. Reload only after checking the effective limits of the actual service; changing an interactive shell’s ulimit does not automatically change a daemon launched by systemd or another supervisor.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
worker_processes auto;
worker_rlimit_nofile 200000;

events {
    use epoll;
    worker_connections 50000;
}

The values in this snippet are configuration examples, not a universal prescription. The descriptor limit must be compatible with the number of workers and with whether each client also creates an upstream connection. A four-worker proxy configured for 50,000 connections per worker is a very different target from a four-worker proxy configured for 12,500 per worker.

Size workers and connection ceilings together

Understand the per-worker calculation

Start with the number of workers you intend to run, then assign a per-worker connection ceiling that leaves descriptor and memory headroom. With four workers and a per-worker limit of 12,500, the configured aggregate is 50,000 client-side connection slots. If every flow is proxied and consumes a second socket, the descriptor requirement can approach twice that client count, plus overhead.

Do not assume that increasing worker_connections increases throughput. It raises the number of sockets a worker is allowed to track; CPU, bandwidth, TLS handshakes, application queues and upstream response time still determine whether those sockets remain healthy.

Keep workers from being monopolized

For static responses, NGINX documents sendfile, which can copy data directly between file descriptors. The sendfile_max_chunk directive can limit how much one fast connection transfers in a single operation, preventing it from monopolizing a worker while other game or API clients wait.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
http {
    sendfile on;
    sendfile_max_chunk 1m;
}

Choose a chunk limit after observing latency and throughput for your workload. It does not reduce the number of open sockets; it controls how aggressively a worker serves a fast transfer.

Make the listen backlog large enough for bursts

The listen backlog holds connections waiting to be accepted. It matters when clients arrive in a burst or workers are briefly busy, but it does not create application capacity and cannot make a host process 50,000 active sessions by itself.

NGINX’s Linux tuning example raises net.core.somaxconn from an example default of 128 to 4096 and uses listen ... backlog=4096. Apply that as a starting example to measure, not as a universal 50,000-connection setting.

sysctl -w net.core.somaxconn=4096
server {
    listen 443 ssl backlog=4096;
}

Ensure the kernel maximum and the application’s listen backlog agree. Observe accept rate, queue depth, connection failures and latency during a burst; a larger queue can delay failure without fixing a slow accept loop or overloaded backend.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Account for HTTP, WebSocket and TLS behavior

Long-lived WebSockets

WebSockets keep connections open, so descriptor count and per-connection memory dominate when message traffic is low. Set idle and ping timeouts deliberately, remove dead sessions, and make sure the application closes sockets when a player disconnects or a match ends. A stale connection that remains counted is indistinguishable from a real player in the concurrency total.

When proxying an upgraded connection, budget for both sides of the proxy and for any buffers or queues used by the application. Upstream failures should release both descriptors promptly; otherwise a backend outage can turn into a descriptor leak at the edge.

HTTPS and reconnect storms

Established encrypted connections and new TLS handshakes have different CPU profiles. A reconnect storm after a regional outage or game-server restart can be harder than 50,000 steady connections because every client negotiates again in a short interval. Test handshake rate, certificate operations and session reuse separately from the steady-state connection count.

Connection lifetime, keep-alive policy and client retry behavior should be part of the load model. A low steady-state count with aggressive retries can produce a higher accept and handshake rate than a larger but stable population.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the right overload control for the problem

Limit simultaneous connections with limit_conn

NGINX’s limit_conn_zone and limit_conn directives cap simultaneous connections using a chosen key, such as an address or account identifier. Use them to reserve capacity for the whole service or for a class of clients. A per-IP limit can be unfair when many players share a carrier-grade NAT, school network or household address, so choose the key with that deployment reality in mind.

Limit request arrival with limit_req

limit_req controls request arrival rate with a leaky-bucket method. It addresses a different problem from open-connection count: one persistent WebSocket may generate too many messages or HTTP requests without opening new sockets. Configure the rate key, burst behavior and rejection or delay policy to match login, matchmaking and gameplay endpoints separately.

Control bandwidth independently

Bandwidth limits address transfer cost, not descriptor count or request rate. A few clients downloading large assets can saturate the link while thousands of idle sockets consume little bandwidth. Monitor egress and ingress separately and apply bandwidth controls where large downloads would interfere with latency-sensitive game traffic.

Plan reverse-proxy topology and upstream capacity

When NGINX fronts game, API or WebSocket services, count client and upstream sockets. A single edge host can accept 50,000 clients yet overwhelm a smaller backend pool. NGINX documents upstream load balancing; distribute connections across backend servers and set backend limits so one failed or slow node does not consume all edge resources.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Compare a single tuned host with a load-balanced pool on more than raw connection count:

Decision axis Single host Load-balanced pool
Descriptor headroom One machine must hold all client and upstream descriptors. Descriptors are spread across edge and backend nodes.
Failure isolation A host failure affects the entire population. Capacity can be divided so one node failure removes only part of service.
TLS and accept rate One CPU package handles the handshake and accept burst. Handshake and accept work can be distributed.
Upstream sockets One proxy concentrates backend connections. Several proxies can reduce per-node backend pressure.
Observability Simpler to inspect, but a single bottleneck can be harder to isolate. Requires per-node and aggregate metrics.
Scaling path Vertical limits arrive sooner. Additional edge or backend nodes provide a horizontal path.

NGINX Plus documents active-connection limits for upstream servers. If you use that capability, size it against backend memory, worker queues and game-session limits rather than setting an arbitrary number.

Do not guess RAM or CPU requirements

No universal hardware figure establishes that a server can sustain 50,000 connections. The required CPU and memory depend on protocol, TLS handshake rate, payload size, compression, timeout settings, logging, application state and upstream work. A machine that holds 50,000 idle sockets may fail quickly under 50,000 active encrypted streams.

Measure at least these resources during a representative test:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Resident memory for NGINX, the game process, socket buffers and connection-specific queues.
  • CPU utilization by worker, TLS operations and application threads.
  • Open-file usage per worker and the remaining system-wide file-handle margin.
  • Network throughput, packet rate, retransmits and interface errors.
  • Accept rate, active connections, closes, handshake failures and connection errors.
  • Upstream connection count, backend response time and queue depth.
  • Request or message latency at p95 and p99, not only averages.

Publish or rely on benchmark results only when the hardware, kernel, NGINX version, workload and test method are specified. Results from a different protocol or connection lifetime do not establish capacity for your game service.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Load-test the failure modes players will experience

  1. Model the mix. Specify the percentage of idle, active, reconnecting and downloading clients; message frequency; payload sizes; TLS usage; and whether each connection is proxied.
  2. Ramp gradually. Increase open connections and request rate separately so you can identify the first saturated resource.
  3. Test bursts. Simulate a match release, regional reconnect storm or backend restart, not only a smooth ramp to 50,000.
  4. Watch limits. Confirm effective file limits, worker connection usage, kernel backlog behavior and upstream sockets while the test runs.
  5. Record tail latency. Capture p95 and p99 latency, connection-establishment time, error rates and disconnect reasons.
  6. Repeat after each change. A larger backlog or connection limit is useful only if measured latency and error behavior improve without exhausting another resource.

Troubleshoot common capacity failures

“Too many open files” appears first

Check the running service’s LimitNOFILE, the worker’s effective limit, worker_rlimit_nofile, system-wide file handles and the client-plus-upstream descriptor calculation. Raising only worker_connections cannot bypass a lower open-file ceiling.

Connections stop below the configured total

Inspect per-worker distribution, because one busy worker can reach its ceiling while others have room. Then check whether reverse proxying consumes a second descriptor, whether a listener or upstream pool has its own cap, and whether memory pressure or application limits are forcing closes.

Bursts produce connection refusals

Measure accept rate and backlog occupancy. Confirm that net.core.somaxconn is at least as large as the configured listen backlog, then determine whether workers or the backend are accepting slowly. Increasing backlog alone only queues more work.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Latency rises while connection count is stable

Look at CPU, TLS handshakes, bandwidth, upstream response time, application queues and worker monopolization during large transfers. For static data, evaluate sendfile and sendfile_max_chunk; for request floods, use request-rate controls rather than only connection limits.

One client address consumes unfair capacity

A per-IP connection limit may group many legitimate players behind one NAT address. Use an identity or account key where authenticated traffic permits it, or set a policy that distinguishes shared networks from abusive clients.

A practical rollout sequence

  1. Document the target protocol, connection lifetime, message or request rate, payload size, TLS behavior and proxy topology.
  2. Deploy an event-driven Linux configuration and verify that NGINX is using epoll.
  3. Choose worker count and a per-worker worker_connections ceiling from the measured workload, not the headline number alone.
  4. Calculate client and upstream descriptors, then align systemd LimitNOFILE, NGINX worker_rlimit_nofile, worker limits and system-wide file-handle settings.
  5. Set a measured listen backlog and matching net.core.somaxconn value for burst tolerance.
  6. Separate connection, request-rate and bandwidth policies with limit_conn, limit_req and transfer controls where each is appropriate.
  7. Enable efficient static-file handling when applicable and prevent a fast transfer from monopolizing a worker.
  8. Load-test steady state, reconnect storms, backend failures and large transfers while collecting tail latency and resource metrics.
  9. Move to a load-balanced pool when descriptor, CPU, network, failure-isolation or upstream limits make one host the bottleneck.

Example configuration skeleton

This skeleton shows where the major controls belong. Replace the values after measuring your own workload and ensuring the service manager permits the required descriptor count.

worker_processes auto;
worker_rlimit_nofile 200000;

 events {
    use epoll;
    worker_connections 12500;
}

http {
    sendfile on;
    sendfile_max_chunk 1m;

    limit_conn_zone $binary_remote_addr zone=per_ip:10m;
    limit_req_zone  $binary_remote_addr zone=req_rate:10m rate=20r/s;

    upstream game_backends {
        server 10.0.0.11:8080;
        server 10.0.0.12:8080;
    }

    server {
        listen 443 ssl backlog=4096;
        limit_conn per_ip 200;
        limit_req zone=req_rate burst=40 nodelay;

        location / {
            proxy_pass http://game_backends;
        }
    }
}

The example uses four workers only if the operating system and process model produce four workers; worker_processes auto selects according to the host. A per-worker value of 12,500 is illustrative: the aggregate client ceiling and descriptor requirement change with worker count and with the number of upstream sockets. The per-IP and request-rate values are also policy examples, not universal game-service defaults.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Bottom line

Fifty thousand concurrent connections is achievable only as a tested workload, not as a single magic setting. Build around Linux event-driven I/O, size per-worker connections and open-file limits together, count upstream descriptors, tune the backlog for bursts, apply the correct type of overload limit, and validate the complete stack under realistic steady-state and failure traffic. If one host cannot maintain tail-latency and failure-isolation targets with adequate headroom, distribute the connections across a load-balanced pool.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More quests from Patch Notes

  1. How to Set Up a RedM (RDR2) Server in 2026: License Key, txAdmin and server.cfg, Step by StepBlog11min
  2. Best RedM (RDR2) Server Hosting in 2026: Comparing Four Hosts on Slots, Memory and PriceBlog10min
  3. How to Host a Mindustry Server in 2026: server-release.jar, Port 6567 and the Commands That MatterBlog7min
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.