Almost every game server tutorial you have read says “increase the socket buffers” and stops there. In practice, undersized UDP receive buffers are one of the most common causes of a server that reports perfect CPU and RAM utilisation while players still see hit-registration gaps, rubber-banding, or “Connection timed out” during a base raid. The kernel silently drops datagrams that arrive when the socket queue is full, and nothing in the game logs tells you. This is a measurement and platform problem as much as a tuning one, which is why operators who run their own bare-metal game servers with full kernel access have a decisive advantage over managed shared plans that hide sysctl.
What Actually Happens When the Buffer Fills
Each UDP socket has two limits: net.core.rmem_default (what a socket gets without asking) and net.core.rmem_max (the ceiling a program can request with SO_RCVBUF). Linux doubles the value you set, so an rmem_max of 4 MiB yields an 8 MiB effective receive buffer. When the queue is full, the kernel drops the newest packet and increments the RcvbufErrors counter in /proc/net/snmp under Udp:.
The relevant columns are InErrors, which includes buffer drops, and NoPorts. If InErrors climbs during peak load while the CPU is idle, you have a buffer or scheduling problem, not a game-code problem.
# watch UDP buffer drops once per second
watch -n1 "awk '/^Udp:/{getline v; print v}' /proc/net/snmp"
How Much Buffer a Game Server Really Needs
The buffer must cover the worst burst, not the average rate. A practical estimate:
| Workload | Avg packet rate | Peak burst (5 s) | Suggested rmem_max |
|---|---|---|---|
| Minecraft (64 players) | ~6k pkt/s | 12k pkt/s | 4 MiB |
| CS2 (20 slots, 128 tick) | ~9k pkt/s | 22k pkt/s | 8 MiB |
| Rust (200 players, raid) | ~25k pkt/s | 70k pkt/s | 16 MiB |
| FiveM (128 slots, OneSync) | ~30k pkt/s | 90k pkt/s | 32 MiB |
Convert burst to bytes: at ~280 bytes average UDP payload plus ~60 bytes of headers and sk_buff overhead, 70k pkt/s is roughly 24 MB/s. A buffer of 16 MiB therefore holds under one second of traffic. That is the design target: enough to ride out a 200–400 ms scheduler stall or NIC interrupt storm without dropping a frame of input.
Tuning Values That Hold Up Under Load
net.core.rmem_max = 33554432andnet.core.rmem_default = 4194304— ceiling for the big FiveM/Rust instances, sensible default for everything else.net.core.wmem_max = 33554432— the send side matters too; outbound bursts to 200 clients queue in the socket before the qdisc.net.core.netdev_max_backlog = 5000— softirq queue length; raise to 8192 on 10GbE hosts with many instances.net.core.somaxconn = 1024— relevant for query and panel TCP listeners.net.ipv4.udp_mem = 65536 131072 262144— global page limits; each page is 4 KB, so this allows ~1 GB total UDP memory across all sockets.
The last one is the trap. Raising rmem_max with a default udp_mem can push the kernel into global UDP memory pressure, at which point it drops from every socket at once. On a 16-instance node, budget instances × per-socket peak × 1.5 in pages.
Does the Game Server Even Ask for It?
Raising rmem_max only helps if the process calls setsockopt(SO_RCVBUF). Many dedicated servers do not, or request a fixed small value. Check per-socket reality:
ss -uanmp | grep -A1 ':27015'
Look for skmem:(r<rcvbuf>). If rcvbuf is still ~212992 even after the sysctl, the application uses the default. Options: set rmem_default high globally, or wrap the binary with an LD_PRELOAD shim that forces SO_RCVBUF on every UDP socket. The preload route is ugly but effective and survives game updates, unlike patching.
Size From Bursts, Not Averages
Raid nights produce bursts of correlated events — dozens of players entering the same area, then a wave of entity-spawn packets hitting the server within the same 100 ms. A 200-player Rust server that averages 25k pkt/s has produced 5-second peaks near 90k pkt/s in our captures. If you size from the average, or even the 95th percentile of a quiet hour, the buffer will overflow exactly when the server matters most.
Capture the distribution rather than estimating it. A short tcpdump sample during a raid, cut into 1-second buckets, gives you the peak-per-second histogram you need:
tcpdump -i eth0 -nn -s0 udp portrange 27000-27100 -w raid.pcap -G 600 -W 1
tshark -r raid.pcap -qz io,stat,1 | sort -k3 -n | tail -20
Set rmem_max to cover roughly twice the highest 1-second bucket you observe, multiplied by average packet size. That has held up across Rust, FiveM and CS2 in our tests without wasting memory outside peak windows.
Buffer Sizing Is Not a Fix for CPU Starvation
A buffer buys time, nothing more. If the receive path is single-threaded per socket (it is, on stock Linux), a 200-slot Rust server pushing 25k pkt/s on one core will eventually overflow any buffer because the drain rate is bound by softirq and the game’s own recv loop. Confirm the real cause before you add memory:
mpstat -P ALL 1— is one core pinned at 95%%soft? Then the fix is RPS/RFS or spreading instances across queues, not buffer size.ethtool -S eth0 | grep drop— NIC-level drops mean the ring buffer is too small, not the socket one.nstat -az | grep -i 'UdpRcvbufErrors'— clean cumulative view per interface.
Typical ordering of fixes when you see UDP drops: enlarge the NIC ring (ethtool -G eth0 rx 4096), raise netdev_max_backlog, enable RPS across cores, then raise socket buffers. Doing it in the other order masks the symptom and wastes RAM.
Verification Before and After
Run a load test with synthetic clients, record UdpRcvbufErrors per 1,000 packets received, and re-test after each change. On a 200-slot Rust instance we cut buffer drops from 0.4% to under 0.01% by going from a 208 KB default to a 16 MiB effective buffer plus RPS on four queues — the players noticed hit registration before we showed them the graph.
This level of control requires root on the host and a kernel you can tune without a ticket, which is exactly what a dedicated game server on dedicated hardware gives you. Measure first, tune in the order above, and keep the counters on a dashboard so the next raid night is not a surprise.


Leave a Reply
You must be logged in to post a comment.