← Blog

Minecraft Server TPS: How to Diagnose and Fix Lag on Your World

By Benjamin D. · PDG

· 9 min read

Illustration for the article: Minecraft Server TPS: How to Diagnose and Fix Lag on Your World
Contents

Minecraft server TPS falls below 20 the moment a single tick needs more than 50 ms to complete, and the cause is always measurable: too many ticking entities, chunks generated on the main thread, a redstone contraption, or one plugin walking the entire world every tick. Profile first, then tune. Guessing wastes hours and usually makes the world worse.



TPS, MSPT and the 50 ms tick budget

The server runs the world 20 times per second. Each of those ticks gets 50 ms to move mobs, run pathfinding, tick blocks, process redstone, save chunks and answer packets. Finish under 50 ms and TPS stays at 20. Go over, and the tick loop simply falls behind.

That is why MSPT (milliseconds per tick) is the useful number, not the TPS average. A world sitting at 45 ms MSPT reports a perfect 20 TPS while being one mob farm away from collapsing. TPS only tells you the damage has already happened.

Average MSPTReported TPSWhat players notice
Under 30 ms20Nothing, healthy headroom
40 to 50 ms20 with spikesOccasional block-place delay
50 to 70 ms15 to 19Stuttering mobs, slow hoppers, laggy doors
Over 100 msUnder 10Rubber-banding, hits not registering, timeouts

Single-thread performance sets the ceiling because the main tick loop cannot be split across cores. A high-clock chip such as a Ryzen 9 7950X3D with DDR5 ECC memory and NVMe storage gives more room per tick, which is what a machine tuned for Minecraft server hosting is built around. Tuning still matters: no CPU survives 4000 ticking entities.



Diagnosing Minecraft server TPS with spark

Stop reading chat complaints and start reading numbers. On Paper, Purpur or Fabric, the spark profiler is the standard tool, and it replaced the old timings reports. Install it as a plugin or mod, then work through three commands before changing a single setting.

Live health check

/tps
/mspt
/spark health
/spark tickmonitor --threshold 100

/spark health returns TPS, MSPT percentiles, CPU load and memory use in one block. The tick monitor prints a line every time a tick crosses your threshold, which is how you catch a spike that happens every 30 seconds instead of a constant slowdown.

A real profile, not a screenshot

/spark profiler start --timeout 300 --only-ticks-over 100
/spark profiler stop

Let it run while the server is actually loaded: peak hours, farms running, players spread across dimensions. The --only-ticks-over filter samples just the bad ticks, so the report points at the culprit instead of averaging it into noise. Read the call tree from the widest branch down.

What the tree usually says

  • ServerLevel.tickEntities dominant: entity problem, go to the next chapter.
  • ChunkMap or ServerChunkCache heavy: chunk generation or loading.
  • LevelChunk.tickBlockEntity with hoppers listed: container and redstone contraptions.
  • A plugin package name high in the tree: that plugin's scheduler or listener.
  • NioSocketChannel writes climbing: too much entity data broadcast per player.

Keep the report link. Fix one thing, reprofile, compare the MSPT percentiles. Changing eight settings at once teaches you nothing, and you will not know which one to roll back. The same method applies to every ticking sandbox game listed on All our game servers.



Entities: the biggest tick eater in most worlds

On a public survival world, entities are responsible for the majority of lost ticks. Every mob runs AI and pathfinding, every dropped item checks for merges, every minecart and armor stand ticks. Item frames and armor stands in a busy spawn build add up quietly.

Find them before capping them. /spark heapsummary or a plugin that counts entities per chunk will expose the one chunk with 900 chickens. Ask the owner to move it, or cap breeding with a mob-limit plugin instead of nuking the farm.

Activation ranges and merging

# spigot.yml
world-settings:
  default:
    entity-activation-range:
      animals: 16
      monsters: 24
      raiders: 48
      misc: 8
      water: 8
      villagers: 16
      flying-monsters: 48
      tick-inactive-villagers: false
    merge-radius:
      item: 3.5
      exp: 4.0

Activation range decides how far from a player an entity keeps running full AI. Lowering monsters from 32 to 24 is invisible in gameplay and cuts pathfinding work sharply. Merge radius reduces dropped-item counts from farms, at the cost of slightly chunkier item stacks on the ground.

Spawn limits and spawner rates

# bukkit.yml
spawn-limits:
  monsters: 40
  animals: 8
  water-animals: 3
  water-ambient: 8
  ambient: 1
ticks-per:
  animal-spawns: 400
  monster-spawns: 2
  autosave: 6000

On Paper, enable per-player-mob-spawns so the mob cap is calculated per player rather than globally. Without it, one player at a farm starves everyone else of mobs while the cap stays full. With it, lowering the monster limit hurts far less than people expect.

# paper-world-defaults.yml
entities:
  spawning:
    per-player-mob-spawns: true
    despawn-ranges:
      monster:
        hard: 96
        soft: 32
  behavior:
    disable-chest-cat-detection: true


Chunk loading, pregeneration and view distance

Generating a chunk is one of the heaviest single operations the server performs. A player flying an elytra over fresh terrain, or a nether portal opening into unexplored land, forces generation on the main thread and produces exactly the spikes the tick monitor reports.

The fix is pregeneration plus a world border. Use Chunky while nobody is connected, then lock the border so nothing new is generated during play.

/chunky world world
/chunky center 0 0
/chunky radius 5000
/chunky start

/minecraft:worldborder center 0 0
/minecraft:worldborder set 10000

View distance and simulation distance

# server.properties
view-distance=7
simulation-distance=5
entity-broadcast-range-percentage=75
sync-chunk-writes=false
max-tick-time=60000

Simulation distance is the expensive one: it defines how far the world actually ticks. Dropping it from 10 to 5 removes a huge amount of block and entity work while players still see terrain at view distance. Keep view distance at 7 or higher so the world does not look cropped.

Autosave is the other periodic spike. Spread it out rather than dumping everything at once, and keep the save interval aligned with your backup window.

# paper-world-defaults.yml
chunks:
  autosave-interval: 6000
  max-auto-save-chunks-per-tick: 8
  entity-per-chunk-save-limit:
    experience_orb: 50
    snowball: 20
    arrow: 20


Redstone, hoppers and player-built lag machines

One observer clock left running in a chunk that stays loaded can cost more MSPT than fifty players walking around. Redstone updates cascade, and vanilla's update algorithm is notoriously wasteful on large circuits.

Paper ships an alternative implementation that handles wire updates far more efficiently, with identical behaviour for almost every build. Hoppers get their own treatment: the move event is what most economy and protection plugins listen to, and disabling it removes thousands of listener calls per second.

# paper-world-defaults.yml
misc:
  redstone-implementation: ALTERNATE_CURRENT
hopper:
  disable-move-event: true
  ignore-occluding-blocks: true
tick-rates:
  mob-spawner: 2
  container-update: 3
  grass-spread: 4

Check what your plugins need before switching off the hopper move event: some sorting and shop plugins depend on it. Reprofile after the change and confirm tickBlockEntity dropped.

Locating the offending chunk

  1. Run /spark profiler start --only-ticks-over 80 during a spike window.
  2. Look for HopperBlockEntity, ObserverBlock or PistonBaseBlock in the tree.
  3. Use an entity or tile-entity counter to list the heaviest chunks and their coordinates.
  4. Teleport there, break the clock or cap the hopper chain, and tell the builder what to change.

Publishing rules about 0-tick farms, flying machine loops and unfiltered item-elevator designs saves more ticks than any config file. Communities accept limits when they understand the reason; reference documented behaviour rather than opinion when you explain it.



Plugins, JVM flags and disk behaviour

Plugins rarely lag by existing; they lag by scheduling badly. A land-claim plugin scanning every block change, a chat plugin resolving player data on the main thread, or two plugins doing the same job both hook the same events twice. The spark tree names the class, so you can act instead of deleting half your folder.

Memory and garbage collection

Set -Xms equal to -Xmx so the heap never resizes mid-tick, and give the JVM less than the machine's total memory so the operating system keeps room for chunk caching. Modern Java releases with G1GC handle large heaps well when the flags are sane.

java -Xms8G -Xmx8G \
  -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:SurvivorRatio=32 \
  -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 \
  -jar paper.jar nogui

More RAM does not raise TPS. An oversized heap lengthens garbage collection pauses, which show up as regular spikes in the tick monitor. Size it to the world and modpack, not to whatever the machine has available. Recommended reading on flag behaviour lives in the official PaperMC documentation.

Disk, backups and watchdog

  • Run the world on NVMe storage: chunk writes on spinning or network storage stall the tick loop.
  • Schedule automatic backups outside peak hours, and never snapshot the world folder while autosave is writing.
  • Keep max-tick-time high enough that the watchdog does not kill the process during a legitimate long save.
  • Restart daily if you run a heavy modpack: it clears fragmented heap and stuck chunk tickets.

Version choice matters too. A recent Paper build includes optimisations that no config file can replicate, and modded worlds benefit from server-side performance mods such as Lithium on Fabric. More administration walkthroughs are collected on the Nexus Games blog.



Conclusion

Profile before you edit anything. Nine worlds out of ten recover most of their lost ticks from three actions: dropping simulation distance, capping entity counts per chunk, and switching redstone plus the hopper move event to the efficient behaviour. The mistake to avoid first is throwing memory at the problem: an oversized heap adds garbage collection pauses and hides the real culprit. Measure, change one thing, measure again.



FAQ

How much RAM does a Minecraft server need to keep 20 TPS?

A vanilla or Paper world with ten to twenty players runs comfortably on 4 GB allocated to the Java heap. A medium plugin setup wants 6 GB, and a large modpack with generated structures usually needs 8 GB or more. Beyond that, extra memory does not add ticks; it lengthens garbage collection pauses. Size the heap to the world, leave memory for the operating system, and verify with a profiler rather than adding gigabytes blindly.

Is switching from vanilla to Paper enough to fix lag on its own?

Paper alone typically recovers a meaningful amount of tick time because it fixes inefficient vanilla routines and adds async chunk handling. It will not save a world with 3000 mobs in one chunk or a permanently running observer clock. Treat the software swap as step one, then tune entity activation ranges, simulation distance and hopper behaviour. The combination is what keeps a busy world stable during peak hours.

Why does the console report 20 TPS while players still complain about lag?

Because TPS measures the world simulation, not the connection. If ticks are healthy, the problem is network latency, packet loss on the route, a client-side frame rate issue, or too much entity data pushed to each player. Check ping values in the console, lower entity-broadcast-range-percentage, and ask affected players to test on a wired connection before assuming the machine is at fault.

Read next

Minecraft server rental

10,000+ 1-click modpacks

from $8.12/mo

Rent my Minecraft server