The ping is the cheapest attack there is
Every Minecraft client that shows your server in its list sends a status request: what version, how many players, what message. Answering is completely normal behaviour, and it is what makes your listing show anything at all.
It is also free to send and slightly expensive to answer, and there is no authentication in front of it. That combination has made the server-list ping a standing way to hammer a server that has done nothing wrong. It does not kick anybody out of the world, so it is easy to dismiss — right up until you notice that during a ping flood your listing goes dark, everyone browsing for a server sees a dead entry, and the people you already have start asking whether the server is down.
The fix is to stop your server answering them
If something in front of your server answers status requests from a snapshot it holds, and refreshes that snapshot on an interval regardless of how many pings arrive, then the asymmetry disappears. Ten pings and ten million pings both cost your server the same thing: one refresh per interval. The flood costs the network in front of you a cached lookup, which is the cheapest operation in the system.
Two details separate an implementation that helps from one that hurts:
Never fake the protocol number. It is tempting to answer with a fixed value, but the protocol number is what tells a client whether it can join. A wrong one makes every client display "incompatible version", and your server looks broken rather than protected — which is worse than the flood you were defending against.
Keep the snapshot fresh enough to be honest. A player count from ten minutes ago is a listing that lies. The refresh interval is a real trade between accuracy and origin load, and it should be short enough that the numbers people see are the numbers they get.
The other half: what happens when the server is genuinely full
A full server is not an attack. It is success, and most servers handle it in the worst possible way: the arriving player gets a rejection message and goes to find another server.
A queue changes that from a rejection into a wait. The player is held, shown where they stand in line and roughly how long it will take, and admitted as slots free up. The difference in outcome is not subtle — a player who can see they are 47th and moving will usually wait, and a player who got an error will not.
There is a second reason a queue belongs in front of the server rather than inside it. A queue implemented as a plugin still requires the player to connect to the server to be told to wait, which means the server is spending resources on everybody who is waiting. A queue in front holds them without the server knowing they exist.
Where a queue belongs in the order
The ordering matters and it is easy to get backwards.
After the challenge. A queue position should cost a bot the same proof a join does. If arrivals are queued before being challenged, an attacker fills the line with connections that were never going to play, and your real players wait behind them. Making the challenge come first means a bot pays for a solve before it can take a position at all.
Before the rate limits. Admission buys a seat, not immunity. A player who reaches the front of the queue is still subject to every per-address limit, every ban, and every other check. A queue that grants exemptions turns into the thing attackers aim for.
The hard part: one queue, many locations
If your protection runs in more than one location — which is the point of a global network — then the queue has a genuinely difficult problem underneath it. Each location can only see its own arrivals, and a player's position is supposed to be their position in a single global line.
An honest implementation is clear about which parts are exact and which are approximations:
- The cap — how many players may be connected at once — has to be exact, because it is what the customer's plan is measured against. That means summing what every location reports. Summing has a known bias: a player who reconnected and landed on a different location can be counted twice. That overstates and can never understate, which is the safe direction for a number that gates admission.
- The position is harder. Ordering a global line identically everywhere with no coordination between locations requires a shared watermark, and until every location has one, a waiting player's position is their position among the arrivals that location can see. It is an approximation, and it should be described as one.
- The estimated wait is derived from how fast the line has recently been draining, which is a moving average of a noisy quantity. It deserves to be shown coarsely. A per-second countdown implies a precision that does not exist.
And there is the failure mode to plan for: if the coordinating service goes quiet, each location has to fall back to its own count, which means each behaves as if it owned the whole cap. Admission can overshoot during such an outage. That is a deliberate trade — the alternative is a coordination outage becoming a total outage for the customer, which is worse.
Both of these are protection, not features
It is easy to file a status cache and a queue under "nice to have". Under attack they are neither.
The status cache is what keeps your server discoverable while somebody is trying to make it invisible. The queue is what keeps a traffic spike — including the legitimate kind, after a video or an event — from turning into a wall of rejections that sends your new players somewhere else. Both work by moving a cost off your machine and onto something built to absorb it, which is the same idea behind everything in Minecraft server DDoS protection.
Itnetic's game protection answers server-list pings from a cached snapshot and holds arrivals in an ordered queue when a server is at its player limit.