Minecraft 1.21 Server Lag Fix and Optimization 2026

Published on | Updated

Check /tps and /mspt to name the problem, then fix it: Purpur, Aikar or ZGC flags, lower simulation distance, entity limits and Chunky pre-generation.

minecraft 1 21 fix lag server optimization 2026

Quick Answer: Minecraft 1.21 lag is caused by heavier world generation and more entities, but "lag" is four different problems with four different fixes. Check /tps and /mspt first, then: 1) run Purpur instead of vanilla, 2) drop simulation-distance to 4 or 6, 3) use Aikar's flags with -Xms equal to -Xmx, or ZGC on 8GB and up, 4) pre-generate the world with Chunky, 5) profile with Spark before you buy more hardware. How many players the server holds after that depends mostly on your plugins, farms and mods, so measure it yourself with /tps, /mspt and Spark.


Server Lag or Client Lag? Check This First

Half the lag reports you get are not server lag at all. Split them before you touch a config file.

Server lag (low TPS) affects everyone at the same time. Mobs freeze in place, blocks break with a delay and pop back, hoppers stall, inventories open slowly. You confirm it with /tps.

Client lag (low FPS) affects one player. Their movement stutters, the frame rate drops, but mobs and redstone behave normally for everyone else. They confirm it with the F3 debug screen, bottom right. The fix is on their machine: lower render distance, a client performance mod, better GPU. No amount of server RAM helps.

TPS is server side game logic, 20 ticks per second, 50 milliseconds per tick. FPS is client side rendering. A player with 300 FPS still sees rubber banding when server TPS sits at 14.

What Your TPS Number Means

  • 20 TPS, perfect, every tick finishes inside its 50ms budget
  • 15 to 19 TPS, mild lag, movement stutters and redstone gets sloppy
  • 10 to 14 TPS, heavy lag, block delays and mob freezing
  • Below 10 TPS, effectively unplayable

Anything consistently below 19.5 is worth investigating.


The Four Types of Minecraft Server Lag

Before you fix anything, classify what you are seeing. Throwing RAM at a network problem does nothing, and upgrading the CPU will not stop a garbage collection freeze.

1. TPS Lag (Tick Lag)

Symptoms: block break delays, mob AI freezing, redstone misfiring, items stuck in hoppers, and the console printing Can't keep up! Is the server overloaded?

What is happening: the main thread cannot finish the game logic inside 50ms, so ticks get skipped.

2. Chunk Loading Stutter

Symptoms: smooth at spawn, hitches or full freezes when players walk or fly into new terrain. Elytra flight is the worst case.

What is happening: the server is generating terrain live, which hammers one CPU core and the disk at the same time.

3. Garbage Collection Lag

Symptoms: the server runs fine for a few minutes, freezes solid for a noticeable moment, then resumes. The pattern repeats on a rhythm.

What is happening: the JVM is pausing every thread to clean up unused memory.

4. Network Lag (Desync)

Symptoms: players rubber band backwards, broken blocks reappear, hits do not register. Only some players are affected, not the whole server at once.

What is happening: packets between client and server are delayed or dropped. TPS can be a flat 20.0 while this is going on.


How to Check TPS and MSPT on a Minecraft Server

/tps

/tps

Output:

TPS from last 1m, 5m, 15m: 19.8, 19.9, 20.0

Good is above 19.5 and stable. 17 to 19 means noticeable lag. Below 17 is unplayable.

/mspt

TPS alone hides how close you are to the edge. A server at 20.0 TPS with 49ms ticks is one mob farm away from collapsing. MSPT shows the real headroom:

/mspt
  • Below 40ms, healthy, room to grow
  • 40 to 50ms, warning zone, any spike drops ticks
  • Above 50ms, the server is already skipping ticks

Checking Garbage Collection Activity

If the freezes are rhythmic, log the collector. Add to your startup flags:

-verbose:gc -Xlog:gc*:file=gc.log:time

Then read gc.log. Pauses above 200ms are a problem. A line like this is a two second freeze:

[Full GC (Allocation Failure) 2048M->1800M(2048M), 2.1 secs]

Why Minecraft 1.21+ Is So Much Heavier

The Technical Changes

Minecraft 1.21 "Tricky Trials" and later introduced changes that all cost tick time:

ChangeWhy it costs performance
Trial Chambers (new structure)Complex generation with many entities and spawners
Breeze mobIts own AI and pathfinding
Wind ChargesExtra projectiles to simulate in combat
Copper and Tuff variantsMore block states to keep in memory

How much extra load that adds depends entirely on your world and players, so we won't put a percentage on it. A setup that barely held 20 TPS on 1.20 can fall short on 1.21 with the same hardware and plugins. If your server "suddenly started lagging after the update", nothing broke. The workload grew. Check /mspt and a Spark profile before and after the update to see where the extra time goes.


Step 1: The Right Server Software (Vanilla vs Spigot vs Paper vs Purpur)

1.1 The Server Software Hierarchy

Vanilla (Mojang) → Bad for performance
    ↓
Spigot → Basic optimizations
    ↓
Paper → Excellent optimizations + API
    ↓
Purpur → Paper + configuration freedom, best of the four

Older charts put Pufferfish between Paper and Purpur, because Purpur used to pull in Pufferfish's patches. Current Purpur is built directly on Paper. Pufferfish itself has no build for 26.x (its newest download is 1.21.8), so it is not an option on a current server.

Short version if you just want the ranking:

  1. Purpur, Paper plus a huge config surface. Best for 20+ players.
  2. Paper, async chunk loading and redstone rewrites. Great for 10 to 50 players.
  3. Spigot, vanilla plus basic tweaks. Acceptable for 5 to 20 players.
  4. Vanilla, no optimizations at all. Only for a 2 to 5 player world.

Plugin compatibility is identical across Spigot, Paper and Purpur, so there is no compatibility reason to stay on the slower option.

1.2 Why Purpur

FeatureVanillaPaperPurpur
Async chunk loadingNoYesYes (from Paper)
Entity activation rangeNoYes (spigot.yml)Same as Paper
Redstone optimizationsNoYesSame as Paper
Config optionsFewManyVery many
Villager lobotomize optionNoNoYes
Per mob gameplay settingsNoNoYes

How big the difference is on your server depends on the plugins, farms and player count, so measure it: note /mspt during a normal evening, switch the jar, and compare the same kind of evening afterwards.

1.3 Installing Purpur

Downloads are at https://purpurmc.org/downloads

# SSH to your VPS
ssh root@your-vps-ip

# Create server directory
mkdir -p /opt/minecraft-server
cd /opt/minecraft-server

# Download Purpur (replace the version with the current one)
wget https://api.purpurmc.org/v2/purpur/1.21.1/latest/download -O purpur.jar

# Accept EULA
echo "eula=true" > eula.txt

First start, which generates the config files:

java -Xms2G -Xmx4G -jar purpur.jar nogui

Stop the server after 30 seconds with Ctrl+C. You now have every config file you need for the next steps.


Step 2: server.properties (View Distance and Simulation Distance)

nano server.properties
# === PERFORMANCE CRITICAL ===

# Simulation distance: how many chunks around a player are "active"
# Default 10, lower it to 4 or 6
# This is the single most important setting
simulation-distance=4

# View distance: how far a player can SEE
# Costs bandwidth and chunk tracking, not much tick time
# 10 is fine on decent hardware, drop to 6 or 8 if you are still short
view-distance=10

# Network compression, balance between CPU and bandwidth
# 256 is the sweet spot
network-compression-threshold=256

# Spawn protection, unnecessary on survival
spawn-protection=0

# Ceiling on a single tick before the watchdog kills the server
max-tick-time=60000

# World size cap, keeps generation bounded
max-world-size=10000

# === CHUNK LOADING ===

# Chunks around spawn that always stay loaded
# Lower or 0 for less RAM
spawn-chunk-radius=2

Why Simulation Distance Matters More Than View Distance

Simulation DistanceActive chunks per playerShare of the default
10 (default)441 chunks100%
6169 chunks38%
481 chunks18%

Going from 10 to 4 cuts the number of chunks the server simulates around each player by more than 80%. Players barely notice. Farms run slightly slower and mobs spawn closer, that is the whole trade.

View distance is a different budget. It decides how many chunks the server has to keep tracked and sent to each client, so it costs memory and bandwidth. Cut simulation distance first. If you are still over 50ms MSPT, then bring view distance from 10 down to 6 or 8, which cuts the number of chunks tracked and sent per player by a third or more.


Step 3: purpur.yml (Advanced Purpur Options)

nano purpur.yml
world-settings:
  default:
    # === MOB AI OPTIMIZATION ===
    mobs:
      zombie:
        ridable: false
        aggressive-towards-villager-when-lagging: false

      # Tropical fish do nothing but cost AI time
      tropical_fish:
        ridable: false
        takes-damage-from-water: false

      # Axolotls spawn a lot and do little
      axolotl:
        ridable: false

    # === REDSTONE ===
    # Limit hopper checks, one of the biggest lag sources
    hopper:
      disable-move-event: true

    # === ENTITIES ===
    # Merge dropped items so there are fewer entities
    merge-radius:
      item: 4.0
      exp: 6.0

    # Despawn junk items faster
    alt-item-despawn-rate:
      enabled: true
      items:
        cobblestone: 300
        netherrack: 300
        sand: 300
        gravel: 300

    # === VILLAGERS ===
    villager:
      lobotomize:
        enabled: true
        check-interval: 100
      brain-ticks: 2

    # === PATHFINDING ===
    use-async-pathfinding: true

Lobotomize villagers. Villagers that cannot pathfind, which is every villager in a trading hall, stop receiving AI after 100 ticks. They still trade and still breed, but they cost very little per tick. On a server with a big trading hall this is often the largest single win available.


Step 4: spigot.yml (Entity Activation and Growth)

nano spigot.yml
world-settings:
  default:
    # === MOB SPAWN LIMITS ===
    mob-spawn-range: 6

    entity-activation-range:
      animals: 16
      monsters: 24
      raiders: 48
      misc: 8
      water: 8
      villagers: 16
      flying-monsters: 48

    entity-tracking-range:
      players: 48
      animals: 48
      monsters: 48
      misc: 32

    # === DESPAWN RATES ===
    item-despawn-rate: 3000
    arrow-despawn-rate: 600

    # === MERGE SETTINGS ===
    merge-radius:
      item: 4.0
      exp: 6.0

Entity activation range is how far from a player a mob keeps running its AI. The defaults are generous, 32 for animals and monsters. Halving them means a mob 20 blocks behind a wall stops pathfinding until someone comes back.

Growth modifiers in the same file are often set the wrong way round. 100 is vanilla speed, and a higher value makes crops grow faster, not slower. Paper's documentation describes it as "The growth modifier percentage for cactus, where Vanilla speed is 100%". Lowering the values slows farms down, but the server still random ticks those blocks, so it is not a real performance fix. Leave them at 100 and handle farm output with entity limits and item merging instead.


Step 5: paper-world-defaults.yml (Paper Specific)

nano config/paper-world-defaults.yml
entities:
  spawning:
    spawn-limits:
      ambient: 5
      axolotls: 3
      creature: 8
      monster: 50
      underground_water_creature: 3
      water_ambient: 15
      water_creature: 3

    # Give each player their own mob budget instead of a global pool
    per-player-mob-spawns: true

  behavior:
    tick-inactive-villagers: false

collisions:
  # Stops mob grinders from turning into a physics simulation
  max-entity-collisions: 2

chunks:
  auto-save-interval: 6000
  prevent-moving-into-unloaded-chunks: true
  max-auto-save-chunks-per-tick: 8

environment:
  optimize-explosions: true

anticheat:
  anti-xray:
    enabled: true
    engine-mode: 2

per-player-mob-spawns is the setting most people miss. Without it, one player standing in a mob farm eats the entire server mob cap and everyone else's spawns die with it.

anti-xray engine mode 2 costs some CPU. It is worth it on a public server and worth skipping on a private one that is already tight on tick time.


Step 6: bukkit.yml (Global Spawn Caps)

spigot.yml controls range, bukkit.yml controls raw counts:

spawn-limits:
  monsters: 50
  animals: 8
  water-animals: 5
  ambient: 1

The vanilla monster cap of 70 is high for a server with plugins. Dropping to 50 costs almost nothing in gameplay and takes real work off the tick.


Step 7: How Much RAM to Allocate (and How to Waste It)

Server TypePlayersMods/PluginsMinimum RAMRecommended RAM
Vanilla 1.211 to 10None2GB4GB
Vanilla 1.2110 to 20None4GB6GB
Vanilla 1.2120 to 50None6GB8GB
Light plugins10 to 2010 to 154GB6GB
Heavy plugins20 to 5020+8GB12GB
Light modpack1 to 1050 to 1004GB6GB
Heavy modpack1 to 10150+6GB8 to 12GB
Large modpack10 to 20200+12GB16 to 24GB

Three mistakes that cost more performance than they buy:

  • Do not give every byte of the machine to Java. Leave 1GB to 2GB for the operating system, the panel and backups. A host that starts swapping is far slower than a host with a smaller heap.
  • Do not allocate 32GB because it was on the plan. Bigger heaps mean longer collection cycles. A tuned 12GB heap beats a sloppy 32GB heap on the same box.
  • Do not guess. Run /spark heapsummary and size the heap to what the server actually holds.

Set -Xms and -Xmx to the same value. A JVM that resizes the heap while the game is running produces exactly the stutter you are trying to remove.


Step 8: Java Startup Flags (Aikar's Flags)

8.1 Why Plain java -jar Is Bad

Default java -jar server.jar runs with an untuned collector. Large garbage collections can freeze the server for a noticeable moment, memory is used inefficiently, and players can disconnect on the longer pauses.

8.2 Aikar's Flags for 4GB

java -Xms4G -Xmx4G \
  -XX:+UseG1GC \
  -XX:+ParallelRefProcEnabled \
  -XX:MaxGCPauseMillis=200 \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+DisableExplicitGC \
  -XX:+AlwaysPreTouch \
  -XX:G1NewSizePercent=30 \
  -XX:G1MaxNewSizePercent=40 \
  -XX:G1HeapRegionSize=8M \
  -XX:G1ReservePercent=20 \
  -XX:G1HeapWastePercent=5 \
  -XX:G1MixedGCCountTarget=4 \
  -XX:InitiatingHeapOccupancyPercent=15 \
  -XX:G1MixedGCLiveThresholdPercent=90 \
  -XX:G1RSetUpdatingPauseTimePercent=5 \
  -XX:SurvivorRatio=32 \
  -XX:+PerfDisableSharedMem \
  -XX:MaxTenuringThreshold=1 \
  -Dusing.aikars.flags=https://mcflags.emc.gs \
  -Daikars.new.flags=true \
  -jar purpur.jar nogui

For a 6GB server, replace -Xms4G -Xmx4G with -Xms6G -Xmx6G. Nothing else changes.

8.3 ZGC for 8GB and Larger Heaps

Above roughly 8GB, G1 pause times grow with the heap. ZGC collects concurrently and keeps pauses under 10ms, which is below the point anyone can feel it:

java -Xms8G -Xmx8G \
  -XX:+UseZGC \
  -XX:+ZGenerational \
  -XX:+ParallelRefProcEnabled \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+DisableExplicitGC \
  -XX:+AlwaysPreTouch \
  -XX:ZCollectionInterval=5 \
  -XX:ZAllocationSpikeTolerance=2.0 \
  -Dusing.aikars.flags=https://mcflags.emc.gs \
  -jar purpur.jar nogui

Generational ZGC (-XX:+ZGenerational) is the version you want on a modern JDK. If your Java build rejects the flag, drop that one line and keep the rest.

Run Java 21 (Temurin or another current build). More on flag choice in Aikar's flags explained.

8.4 Startup Script

nano start.sh
#!/bin/bash
java -Xms4G -Xmx4G \
  -XX:+UseG1GC \
  -XX:+ParallelRefProcEnabled \
  -XX:MaxGCPauseMillis=200 \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+DisableExplicitGC \
  -XX:+AlwaysPreTouch \
  -XX:G1NewSizePercent=30 \
  -XX:G1MaxNewSizePercent=40 \
  -XX:G1HeapRegionSize=8M \
  -XX:G1ReservePercent=20 \
  -XX:G1HeapWastePercent=5 \
  -XX:G1MixedGCCountTarget=4 \
  -XX:InitiatingHeapOccupancyPercent=15 \
  -XX:G1MixedGCLiveThresholdPercent=90 \
  -XX:G1RSetUpdatingPauseTimePercent=5 \
  -XX:SurvivorRatio=32 \
  -XX:+PerfDisableSharedMem \
  -XX:MaxTenuringThreshold=1 \
  -Dusing.aikars.flags=https://mcflags.emc.gs \
  -Daikars.new.flags=true \
  -jar purpur.jar nogui
chmod +x start.sh
./start.sh

Step 9: Performance Mods and Plugins Worth Installing

Lithium, Server Side Logic

Lithium rewrites large parts of Minecraft's internals without changing a single gameplay rule: mob pathfinding, block ticking, chunk loading, physics. Nothing a player can see changes, everything gets cheaper.

cd /opt/minecraft-server/mods
wget https://cdn.modrinth.com/data/gvQqBUqZ/versions/latest/lithium-fabric-mc1.21.jar

Lithium is a mod for Fabric (newer versions also exist for NeoForge). It does not load on Paper or Purpur. Those servers rely on their own optimization patches instead.

FerriteCore, RAM Reduction

FerriteCore restructures how block states and other game data are stored in memory, which lowers RAM use. The saving is biggest on modded servers with many blocks and models. On a 4GB server or any modded server, that headroom goes straight back into chunk caching.

cd /opt/minecraft-server/mods
wget https://cdn.modrinth.com/data/uXXizFIs/versions/latest/ferritecore-7.0.0-fabric.jar

Check the RAM graph in your panel before and after installing it to see what it saves on your own pack.

Krypton, Network Optimization

Krypton rewrites the packet layer. It matters once you are past roughly 15 concurrent players, when packet volume rather than tick time starts to dominate.

wget https://cdn.modrinth.com/data/fQEb0iXm/versions/latest/krypton-0.2.8-fabric.jar

For Forge and NeoForge Modpacks

ModFunctionSource
ModernFixGeneral optimizations and faster startupmodrinth.com/mod/modernfix
FerriteCoreRAM reductionmodrinth.com/mod/ferritecore
EntityCullingSkips rendering and some processing for hidden entitiesmodrinth.com/mod/entityculling
CanaryThe Lithium equivalent for Forgemodrinth.com/mod/canary
RoadrunnerAsync chunk loadingmodrinth.com/mod/roadrunner

Install these one at a time and check /mspt after each. Stacking five optimization mods blind is how you end up with a crash you cannot attribute.


How to Fix Lag Spikes Every 30 Seconds (Garbage Collection)

This is the rhythmic freeze: fine for a few minutes, then a hard stop for a noticeable moment, then fine again.

  1. Confirm it. Add -verbose:gc -Xlog:gc*:file=gc.log:time and look for pauses over 200ms.
  2. Set -Xms equal to -Xmx.
  3. Use Aikar's flags on small heaps, Generational ZGC on 8GB and up.
  4. Do not fix it by allocating more memory. A larger heap with the wrong collector makes the pause longer, not rarer.

If the pauses continue with ZGC and a correctly sized heap, you are not looking at a GC problem. Profile with Spark instead.


How to Fix Chunk Loading Lag: Pre-Generate the World

If the server is smooth at spawn and hitches whenever someone explores, you are paying for terrain generation live, during ticks. Generate it up front instead.

Install the Chunky plugin and run it with nobody online:

/chunky world world
/chunky radius 5000
/chunky start

That covers a 10,000 by 10,000 block area around spawn. Depending on the CPU it takes between one and six hours, and it is the single best thing you can do for a server whose players roam.

Two things that make pre-generation stick:

  • Set a world border so players cannot walk past the generated area:
    /worldborder set 10000
    
  • Run on NVMe. Chunk loading is an I/O operation before it is anything else. See the storage table further down.

Full walkthrough in the world pre-generation guide.


Entity and Mob Management (Farms, Items, Grinders)

Entities are the most common cause of TPS lag on an established server, because entity load grows every week the server is up while the config stays where you left it.

ClearLag and Manual Cleanup

The ClearLag plugin removes ground items and excess mobs on a timer:

/lagg clear      # remove dropped items
/lagg killmobs   # kill excess mobs
/lagg area 20    # count entities within 20 blocks

Set auto clear to run every 10 minutes in its config.yml. Be aware that the clear itself causes a brief TPS dip, which is a common answer to "why does the server hiccup on a schedule".

Limit What Players Can Build

Mob grinders, iron farms and villager breeders are where the entities come from. The caps in bukkit.yml and max-entity-collisions: 2 in the Paper config do more than any cleanup plugin, because they stop the entities from existing rather than deleting them after they have already cost you a tick.


How to Find the Plugin or Mod That Is Causing Lag

Spark, the Profiler Worth Learning

cd /opt/minecraft-server/plugins
wget https://ci.lucko.me/job/spark/lastSuccessfulBuild/artifact/spark-bukkit/build/libs/spark-bukkit.jar

In game:

/spark profiler start
# let it run 60 seconds to 3 minutes during real activity
/spark profiler stop

Spark returns a web link with a call tree: which plugin, which mod, which task, which chunk. It tells you the answer instead of letting you guess. During an intermittent problem, run it long:

/spark profiler --timeout 600

There is a deeper walkthrough in the Spark profiler guide.

Memory side:

/spark heapsummary
/spark heapdump

Timings

/timings on
# wait 10 minutes
/timings paste

Read the report by looking for the biggest bars:

  • Entity Tick high, too many entities, cut activation range and despawn rates
  • Tile Entity high, too many hoppers and chests, rework the redstone
  • World Tick high, simulation distance too high

Plugins That Commonly Cost You Tick Time

Costly choiceBetter alternative
WorldEdit on a large pasteFastAsyncWorldEdit (FAWE)
An outdated EssentialsX buildCurrent EssentialsX
PermissionsExLuckPerms
An old Multiverse buildCurrent Multiverse

The pattern is version age, not brand. Abandoned permissions plugins and old world editors are the usual suspects, and heavy logging plugins are worth checking with Spark before you blame the hardware.


Which CPU Do You Need for a Minecraft Server?

Minecraft's main game loop is single-threaded. Clock speed beats core count, every time. Sixteen slow cores will lose to four fast ones.

Good single-thread performance, in the class of chips people actually run servers on:

  • AMD Ryzen 9 7950X, 5.7GHz boost
  • AMD Ryzen 7 5800X, 4.7GHz boost
  • Intel i9-12900K, 5.2GHz boost
  • Budget option, AMD Ryzen 5 5600X, 4.6GHz boost

Avoid old Xeons in the 2.4GHz range, budget Celerons and ARM processors. They benchmark fine on paper for web workloads and fall apart on a tick loop.

Paper and Purpur move some work off the main thread (chunk loading, some mob AI, pathfinding), so extra cores are not wasted, but they never turn a slow core into a fast one. More on picking silicon in the best CPU for a Minecraft server.

Plan guidance on Space-Node (Standard tier prices per month):

  • MC Iron, 4GB for €3.60: vanilla or Paper with a small group
  • MC Lapis, 6GB for €5.40: a plugin SMP with more players
  • MC Diamond, 8GB for €7.20, or MC Special 1, 12GB for €10.80: modpacks or bigger communities

These are starting points. Plugins, farms and mods decide more than the player count, and you can upgrade later without losing the world.


Storage: NVMe vs SSD vs HDD

TypeChunk loadingAuto savePrice
HDDSlow, visible during explorationCan cause noticeable freezesCheap
SATA SSDMuch fasterUsually a small hitch at mostStandard
NVMeFastestRarely noticeableNow common on game hosts

Chunk loading and the five minute auto save are both I/O bound. On an HDD backed server, the auto save alone is enough to produce a visible freeze on a schedule.


How to Fix Rubber Banding and High Ping (Network Lag)

Network lag looks like server lag to players and nothing like it in the metrics. TPS reads 20.0, MSPT is healthy, and people still teleport backwards.

  1. Check who is affected. If it is one or two players, the problem is their connection or their route, not your server. Have them run a traceroute during a lag episode.
  2. Check the server location against your player base. Latency decides how block placement, PvP hits and inventory actions feel. Pick the location closest to most of your players. Ping depends mostly on distance, so a server on the wrong continent feels laggy however fast it is. The plan selector on our Minecraft hosting page shows a live latency check per region before you order.
  3. Look at the time of day. A budget host on a congested network drops packets at peak hours and is clean at 4 AM. That pattern is the network, not your config.
  4. Rule out an attack. If lag spikes correlate with specific events or repeat at odd times, check whether the server is being hit. Filtering handles it without touching legitimate game traffic. See DDoS protection for Minecraft servers.
  5. Set compression sensibly in server.properties:
    network-compression-threshold=256
    
    Lower values send less data and burn more CPU. 256 is the balance point for almost everyone.

Why Is My Server Lagging With Only 5 Players?

Player count is rarely the cause. Work through this order:

  1. Run /tps and /mspt. If TPS is at 20 and MSPT is under 40ms, the lag is client side or network side, and no server change will help.
  2. Check RAM. 2GB minimum for vanilla, 4GB once you have plugins. Then check you are not swapping.
  3. Check the CPU. You want 3.5GHz or better on boost clock. A 2.4GHz core will lag with two players in a redstone build.
  4. Profile with Spark. On a five player server, one bad plugin is usually the entire problem.
  5. Cut simulation distance to 4 and see whether the number moves.

Most five player lag is either an outdated plugin or a cheap core. It is almost never a shortage of memory, which is what people upgrade first.


Why Does the Server Only Lag at Certain Times?

Rhythmic lag has a scheduler behind it. The candidates, in the order they usually turn out to be responsible:

  • Auto save, every 5 minutes by default (6000 ticks). Painful on slow storage, invisible on NVMe.
  • Garbage collection, a brief freeze on a rhythm. See the GC section.
  • Backups, if they run at peak time. Move them to off hours.
  • Plugin tasks, scheduled jobs inside plugins. Spark finds these.
  • ClearLag sweeps, every 10 minutes by default, brief dip each time.

Run /spark profiler --timeout 600 across a full cycle and match the spike to the schedule.


How to Fix "Can't Keep Up! Is the Server Overloaded?"

[WARN] Can't keep up! Is the server overloaded? Running 5000ms behind, skipping 100 ticks

This means a tick could not finish inside 50ms, so the server skipped ticks to catch up. That is the rubber band players feel.

Three causes, in order of frequency:

  1. Simulation distance too high. Drop it to 4.
  2. Redstone and hoppers. Use /spark to find the chunks with the most tile entities. Water streams move items for free where hoppers cost a check per tick.
  3. Not enough CPU. Fewer players or a faster core.

High RAM Use and Server Crashes

Diagnose before you buy memory:

/spark heapsummary
/spark heapdump

Common causes:

  1. Too many entities in spawn chunks. Reduce spawn-chunk-radius to 0 or 2.
  2. A mob farm running unattended. Cap it with entity-activation-range and per player mob spawns.
  3. A leak in a plugin or mod. The heap dump names the class holding the memory. Disable the suspect and watch whether the curve changes.

A server that crashes with OutOfMemoryError after several hours is leaking, not undersized. Adding RAM only moves the crash later in the day.


Can One Server Hold 100+ Players?

Yes, with the right build:

  • 24GB to 32GB RAM
  • A top end Ryzen 9 or i9 class CPU, 5.0GHz or better on boost
  • Purpur, with async work enabled
  • NVMe storage for chunk I/O
  • A tight plugin list, audited with Spark
  • A pre-generated world so nobody is generating terrain at prime time

Past a certain size, the answer is not a bigger box, it is a proxy: split lobby, survival and minigames across backend servers behind Velocity or BungeeCord. See Velocity vs BungeeCord.


When the Hardware Is Actually the Problem

Most lag is configuration. Some of it is not, and it is worth knowing the difference before you spend money.

You have genuinely outgrown the machine when all of the following are true:

  • Spark shows MinecraftServer.tickServer itself as the bottleneck, not a named plugin or mod
  • The main thread sits pinned at 100% CPU
  • Adding players or loaded chunks drops TPS proportionally, in a straight line
  • You have already pre-generated the world, tuned the collector and cut simulation distance

At that point the only fix is more single-thread performance and faster storage. Everything else you do is rearranging the same workload.


Optimization Checklist

server.properties:

  • simulation-distance=4 (6 at most)
  • view-distance=10, lower to 6 or 8 only if MSPT is still high
  • network-compression-threshold=256
  • spawn-protection=0

purpur.yml:

  • villager.lobotomize.enabled: true
  • merge-radius.item: 4.0
  • alt-item-despawn-rate.enabled: true
  • use-async-pathfinding: true

spigot.yml:

  • mob-spawn-range: 6
  • entity-activation-range reduced
  • item-despawn-rate: 3000

Paper config:

  • per-player-mob-spawns: true
  • max-entity-collisions: 2
  • optimize-explosions: true

bukkit.yml:

  • spawn-limits.monsters: 50

Startup:

  • Aikar's flags, or ZGC above 8GB
  • -Xms equal to -Xmx
  • 1GB to 2GB left free for the operating system
  • Java 21

World:

  • Pre-generated with Chunky
  • World border set

Monitoring:

  • Spark installed
  • /tps and /mspt checked after every change, one change at a time

Result: Measure Your Own Before and After

We are not going to show you a made-up before and after table. The gain depends on your world, plugins and players. What you can do is measure it yourself:

  1. Before you change anything, write down /tps, /mspt, RAM use from the panel graph, and how often the console warns "Can't keep up", during a normal busy evening.
  2. Apply the changes from this guide one at a time.
  3. Write down the same numbers on a comparable evening afterwards.

When the fixes work, players notice less rubber banding, chunks that keep up while they walk, combat that registers, and no disconnects during a GC pause.


Where to Start Tomorrow

If you only have an hour, do these in order and check /mspt between each one:

  1. Move to Purpur if you are on vanilla or Spigot.
  2. Set simulation-distance=4.
  3. Fix the startup flags, with -Xms equal to -Xmx.
  4. Pre-generate the world with Chunky and set a border.
  5. Run Spark for 60 seconds under load and read the top of the call tree.

Steps 1 through 3 take about 20 minutes and cover most of the distance. Step 5 is what stops you from guessing on everything after that.


Ready to run an optimized Minecraft server? Space-Node Minecraft hosting runs Ryzen 9 CPUs and NVMe storage, and every plan supports Purpur. Plans start at €2.70 per month for MC Coal (3GB).

Related guides: