Skip to content

Diagnosing Minecraft Server Lag: TPS, MSPT and spark

Tell server lag from client FPS and latency, read TPS and MSPT, profile with spark, and find the entity, plugin or chunk that is eating your ticks.

Updated August 19, 2026
Minecraft

"The server is lagging" is the least useful sentence in server administration, because at least three unrelated problems produce it. This guide is for the person running the server: how to prove which problem you actually have, how to read the numbers, and how to find the specific entity, plugin or chunk that is costing you ticks.

Everything below is for Java Edition. Paper, Purpur, Fabric, Forge and NeoForge all work the same way here; where a step is Paper-only it says so.

Sizing memory rather than diagnosing?

If you already know memory is your constraint and you just want to know what to allocate, Minecraft Server RAM and JVM Flags covers heap sizing, Aikar's flags and Java versions. This page is about finding out whether that is your problem in the first place.

1. Three Problems That All Feel Like Lag

Before changing anything, establish which one you have. They are unrelated and the fixes have nothing in common.

Client FPS (one player's PC) Server lag (the tick loop) Network latency (the path)
Who feels it Just that player Everyone, at the same moment Players in one region, or one player
Symptoms Choppy rendering, stutter when turning, low FPS counter Rubber-banding, blocks reappearing after breaking, mobs sliding, hits not registering High ping, delayed chat, everything smooth but late
What proves it The F3 screen's FPS figure on that PC Server-side MSPT above 50 ms (section 2) Ping in the player list, or /spark ping
Where the fix is That player's graphics settings and drivers This page Routing and server location, not config

The fastest tell: if one player stutters and nobody else does, it is their client. If everyone rubber-bands at the same instant, it is the server. If everything is smooth but a beat late, it is the network. Only the middle case is server lag, and only the middle case is fixable by anything on this page.

A healthy server can still feel laggy

A server holding 20 TPS with 25 ms ticks is doing its job perfectly. If players in one country still complain while players in another do not, that is distance and routing — a network problem, not a tick problem. No config change will fix it; server location will.

2. TPS and MSPT — and Why MSPT Is the Honest Number

The Minecraft server runs the world in a loop. Each pass through the loop is a tick, and the server aims for exactly 20 ticks per second — one every 50 milliseconds. In a tick the server reads incoming packets, moves players and entities, runs mob AI and pathfinding, processes redstone, and sends the results back out.

If a tick finishes in less than 50 ms, the server sleeps for the remainder and starts the next one on schedule. If a tick takes longer than 50 ms, the next one starts late — ticks cannot run in parallel — and everything in the world happens more slowly.

That gives you two metrics:

  • TPS (ticks per second) — how many ticks were completed per second, on average. Healthy is 20.
  • MSPT (milliseconds per tick) — how long each tick took, on average. Healthy is 50 or fewer.

Why MSPT is the metric to watch

TPS is capped at 20 and averaged, so it hides everything until the problem is already severe. A server that spends most ticks at 20 ms and occasionally spends 300 ms on one tick will report a TPS very close to 20 — and players will feel every one of those spikes. MSPT does not hide it, because spark reports the distribution rather than a single figure: minimum, median, 95th percentile and maximum.

That 95th percentile is the number that matches what players experience. If your median MSPT is 22 ms but your 95th percentile is 140 ms, one tick in twenty is nearly three times over budget — and that is a server people describe as "laggy" while its TPS reads 19.9.

20 TPS is a ceiling, not a score

TPS can never exceed 20, so "20 TPS" tells you only that nothing is badly wrong on average. It says nothing about headroom. Two servers can both report 20 TPS while one runs at 10 ms per tick with 80% of its budget spare and the other runs at 48 ms with almost none — and only one of them survives a raid night.

3. Measuring: /spark tps and /tick query

spark is the standard Minecraft profiler and the tool this whole guide is built around. On Paper 1.21 and newer it is already installed — Paper bundles it, and PaperMC calls it "the preferred way to profile Paper". On Fabric, Forge, NeoForge, Velocity and BungeeCord you install it yourself as a mod or plugin from spark.lucko.me.

Run this in the panel's Console or in-game as an operator:

> spark tps
Console

It reports TPS over several windows and MSPT as a distribution, colour-coded green, amber or red. Read the MSPT figures, not the TPS ones.

For a fuller picture:

> spark health --memory
Console

/spark health adds CPU usage, memory and disk to the tick figures — the fastest single command for "is this server healthy?". Add --memory for JVM heap detail and --network for interface statistics.

The vanilla alternative

If you are on a vanilla jar with no plugins or mods, Minecraft has its own tick command:

> tick query
Console

It "outputs the current ticking status and target ticking rate, with information about the tick performance, including average time per tick and percentiles of time per tick". It has been in Java Edition since 1.20.3, requires permission level 3, and cannot be run from a command block. It gives you percentiles like spark does, but nothing about where the time went — for that you need a profiler. The rest of the /tick subcommands are listed in Minecraft Server Commands.

/tick rate is not a performance fix

/tick rate <n> changes the target tick rate, which changes how fast the game world runs — crops, mobs, redstone, everything. Lowering it does not make your server healthier; it makes the game slower and then reports that as normal. Use it for debugging, never as a remedy.

4. Profiling: Finding Where the Time Goes

Numbers tell you that you have a problem. A profile tells you what is causing it.

> spark profiler start --timeout 600
Console

That samples for ten minutes and then returns a URL to a report you can open in a browser or hand to a plugin developer. Paper's own troubleshooting guide gives 300 seconds as a reasonable alternative. The one rule that matters:

Profile while the problem is happening

PaperMC: "For profiling to be effective, the issue you are diagnosing must be actively occurring." A profile taken on an empty server at 4 a.m. tells you what an empty server does. Run it at peak population, or while the lag is being reported.

Chasing spikes rather than general slowness

Steady slowness and periodic spikes are different problems and need different profiles. If your median MSPT is fine but the maximum is terrible, averaging will bury the spike — all the healthy samples cancel it out. spark has two tools for this.

First, catch the spikes:

> spark tickmonitor --threshold-tick 50
Console

/spark tickmonitor watches every tick and prints a chat message whenever one exceeds your threshold. Fifty milliseconds is "the point at which the server has to start catching up". Watch the output while playing and line the messages up with what is happening in-game — a mob farm activating, a player flying into new terrain, a scheduled task firing.

Then, profile only the bad ticks:

> spark profiler start --only-ticks-over 100 --timeout 300
Console

--only-ticks-over discards every tick under the threshold, so the report contains nothing but the laggy ones. spark's own guidance is to pick a value between 50 and 100 ms, always below the duration of the spikes you saw in the tick monitor.

5. Reading a spark Report

The report opens as a tree, and it is less intimidating than it looks once you know the three rules.

Rule one: pick the right thread. You will be shown a list of threads. On a server, the one that matters is Server thread — the tick loop. Other threads are chunk workers, networking and the like; they are rarely your problem.

Rule two: sleeping is good. Near the top of Server thread you will find waitUntilNextTick(). This is the server doing nothing because it finished the tick early, and a high percentage here is what health looks like. spark's own thresholds:

Sleep percentage What it means
~80% The figure in spark's own worked example, which it calls "healthy" — the server spent four fifths of its budget idle
Below 20% "Your server is working pretty hard, and might be lagging on some ticks"
Below 5% "Your server is probably lagging, and has no spare capacity"

Rule three: follow the biggest percentage. Each node shows the share of thread time it consumed. Expand the largest child, then its largest child, and keep going. You will pass through recognisable frames on the way down — MinecraftServer.tickServer(), then WorldServer.tick() (blocks and redstone), EntityTickList.forEach() and WorldServer.tickNonPassenger() (entities), CraftScheduler.mainThreadHeartbeat() (plugin scheduled tasks, and where a badly-behaved plugin shows up). Keep descending until a name is specific enough to act on.

If the method names are gibberish

On 1.21.11 and older, Minecraft's server code is obfuscated, so raw names look like a.b.c(), and Mojang shipped separate mapping files to undo it. From 26.1 those mapping files stopped being published, because the server jar now ships carrying its real class and method names. Either way the spark viewer applies deobfuscation mappings automatically, and if it picks the wrong ones you can set them manually from the dropdown in the top right. Some well-known frames also carry an ⓘ marker explaining in plain English what that part of the server does.

6. The Usual Culprits

Nine times in ten the profile lands on one of these.

Cause How it shows up What to do
Entity density — mob farms, item piles, huge animal pens tickEntities dominating; MSPT rising through a session Cull with /kill @e[type=item], cap entities per chunk, and set spawn limits (below)
Hoppers Hopper frames high; a big sorting system nearby Setting Paper's hopper.disable-move-event to true "dramatically improves hopper performance", but "will break protection plugins and any others that depend on this event"
Redstone Redstone frames high; a clock or flying machine running unattended Switch Paper's misc.redstone-implementation from VANILLA to ALTERNATE_CURRENT
Chunk loading and generation Spikes when players explore or teleport; chunk-load frames prominent Pre-generate the world with a tool such as Chunky, and set a world border
View / simulation distance too high Uniformly elevated MSPT that scales with player count Lower simulation-distance first, then view-distance
A misbehaving plugin A plugin's own package name in the tree, or heavy mainThreadHeartbeat Isolate it — section 7
Auto-save Regular spikes at a fixed interval, roughly every few minutes Raise chunks.auto-save-interval or lower chunks.max-auto-save-chunks-per-tick (default 24)
Garbage collection Freezes not aligned to anything in-game; /spark gc shows long pauses Right-size the heap — Minecraft Server RAM and JVM Flags
Hardware Bad MSPT with few players, no plugins and a fresh world Nothing config-side left. Single-thread CPU speed is the ceiling
The wrong server software Vanilla-jar performance with a plugin-shaped workload Paper and its forks optimise the tick loop heavily — see Minecraft Server Software Compared

The two server.properties keys are the cheapest wins and cost nothing but a restart — both are documented in full in the server.properties reference:

view-distance=8
simulation-distance=6
server.properties

On Paper, the per-world tuning lives in config/paper-world-defaults.yml (and per-dimension in world/dimensions/<namespace>/<key>/paper-world.yml). The keys worth knowing:

entities:
  spawning:
    per-player-mob-spawns: true
    spawn-limits:
      monster: -1        # -1 = inherit bukkit.yml (default 70)
      creature: -1       # -1 = inherit bukkit.yml (default 10)
    entity-per-chunk-save-limit:
      experience_orb: -1 # -1 = no limit; any entity type can be added here
chunks:
  auto-save-interval: default
  max-auto-save-chunks-per-tick: 24
hopper:
  disable-move-event: false
misc:
  redstone-implementation: VANILLA
config/paper-world-defaults.yml (defaults shown)

Two of those are worth spelling out. spawn-limits and auto-save-interval default to inheriting from bukkit.yml, where the real values live (70 monsters, 10 animals per world); set them here only when you want one world to differ. And entity-per-chunk-save-limit accepts any entity type, not just experience orbs — it is the correct fix for a chunk that has accumulated thousands of items or mobs.

Entity activation ranges — how far from a player an entity keeps ticking normally — live in spigot.yml under entity-activation-range, defaulting to 32 for animals and monsters, 64 for raiders and 16 for miscellaneous entities including dropped items.

Change one thing, then measure

PaperMC's advice on copied optimisation configs is unusually direct: if you are seeing "strange entity/farm/redstone/spawning behavior", revert them. Every one of these keys trades some vanilla behaviour for performance. Change one, restart, re-run /spark tps, and keep it only if the number moved.

7. Isolating a Plugin or Mod

If the profile points at a plugin, you already have your answer. If it does not but you still suspect one, use the method PaperMC documents — a binary search:

  1. Stop the server and take a backup. Modifying files on a running server corrupts them.
  2. Rename the whole plugins directory to plugins-disabled and start up. If the problem is gone, a plugin is responsible.
  3. Split the plugins into two roughly equal groups, keeping anything with a dependency relationship together. Disable one group by renaming its .jar files to .jar-disabled.
  4. Start, test, and note which half the problem followed.
  5. Repeat with that half until one plugin remains.

Libraries are not optional

ProtocolLib, Vault, PlaceholderAPI and permissions plugins are libraries that other plugins depend on. Disabling one takes its dependants down with it and produces misleading results. Keep libraries loaded and group dependants with them. Before any of this, check whether the plugin simply has a newer build — see How to install plugins for Minecraft Java Edition.

8. Reading Logs, Crashes and Watchdog Dumps

Not every problem is slow ticks. When something breaks outright, the server tells you where. PaperMC: "If your server crashes, the crash report will be saved in the crash-report directory. If your server didn't crash, those error messages will be stored in the log directory" — that is logs/latest.log. Older logs are compressed rather than left as plain text, so latest.log is the one to open first.

What you are looking for is a stack trace: an error message, an exception type such as java.lang.RuntimeException, and then a run of lines beginning with at. PaperMC's rule for reading them: "The top line of the body of the stack trace will tell you exactly where the problem occurred." If a plugin's name appears anywhere in those lines, that plugin is your first suspect.

Four patterns are common enough to name.

Watchdog dump. The header shouts --- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH --- followed by "The server has not responded for 10 seconds! Creating thread dump". This is not a crash — it is severe lag. A single tick ran for more than ten seconds and Paper dumped the stack to show you where the main thread was stuck. Read the first few at lines; they usually name the culprit directly. Then take a spark profile for the detail.

Failed to bind to port. Either another instance is already running, or server-ip in server.properties is set when it should be blank. Paper: "this option is not a placeholder for your external IP, it controls which network interfaces your server will bind to. Most of the time, it should be left empty." On the panel the port comes from your allocation, so leave both alone.

Chunk saved with a newer version. Server attempted to load chunk saved with newer version of minecraft! means the world was opened by a newer build than the one now running — which happens the moment a world loads once on a newer jar, even if nobody joined. Downgrading a world is not supported. Restore the pre-upgrade backup instead; that is exactly what Managing your Minecraft server keeps them for, and Updating Your Minecraft Server covers doing the upgrade in an order that does not need one.

The server vanished with no crash report. Nothing in the logs, the process simply gone. That is usually the operating system killing it for exceeding its memory limit. Lower -Xmx before assuming you need a bigger plan — the sizing rules are in Minecraft Server RAM and JVM Flags.

9. When the Numbers Look Wrong But Are Not

Two panel readings send people chasing problems they do not have.

High memory usage. Java claims heap and does not give it back, so the figure climbs and stays high. Paper: "Unless you're experiencing out of memory crashes or bad garbage collection (GC) times, high memory usage is expected… This is not a memory leak." A meter pinned near the top is normal.

Low CPU usage while lagging. Also normal, and it is the single most misread signal in Minecraft hosting. The tick loop is one thread. On an eight-core allocation a fully saturated tick loop shows as roughly one core busy and seven idle — which a panel may render as 12% CPU. Paper's guidance is that "single-threaded performance" is what to buy, and that a server should still have "at least 4" threads available for chunk work, networking and GC. If you have hit this ceiling, more cores will not help; a faster core will, and so will moving to a dedicated server.

10. FAQ

Why is my Minecraft server lagging?

Establish which lag you have first: one player stuttering is client-side, everyone rubber-banding at once is server-side, and smooth-but-late is network. For server-side lag, run /spark tps and look at MSPT. Above 50 ms means the tick loop cannot keep up, and the usual causes are entity density, hoppers, redstone, chunk loading, an over-high view distance, or one heavy plugin.

What is a good MSPT for a Minecraft server?

Under 50 milliseconds, because that is the budget for one tick at 20 TPS. Watch the 95th percentile rather than the average — a median of 20 ms with a 95th percentile of 140 ms is a server that feels laggy while reporting close to 20 TPS.

Is TPS or MSPT more important?

MSPT. TPS is capped at 20 and averaged, so it stays near 20 until a problem is severe, and it hides spikes entirely. MSPT reports the distribution — minimum, median, 95th percentile and maximum — which is what players actually feel.

Do I need to install spark?

Not on Paper 1.21 or newer, where it ships with the server. On Fabric, Forge, NeoForge, Velocity or BungeeCord you install it yourself from spark.lucko.me. Note the command prefix differs by platform: /spark on a server, /sparkb on BungeeCord, /sparkv on Velocity.

Is Timings still the right tool?

No. Paper still bundles Timings v2, but it "has been unmaintained for multiple years", was deprecated in favour of spark, and has been off by default since 1.21. Every current Paper guide — Paper's own included — points at spark instead. If you find a tutorial that starts with /timings on, it predates the change.

How do I fix lag spikes rather than constant lag?

Spikes need a different approach because averaging hides them. Run /spark tickmonitor --threshold-tick 50 to catch them as they happen and see what you were doing at the time, then run /spark profiler start --only-ticks-over 100 --timeout 300 so the report contains only the bad ticks.

Why is my CPU usage low if the server is lagging?

Because the tick loop runs on a single thread. One saturated core out of eight reads as low overall CPU usage while the server is completely out of tick budget. It means single-thread speed is your ceiling, not core count.


Made with 💜 by GameServerKings

Need a Minecraft server?

Deploy an instantly-provisioned Minecraft server on high-clock hardware — DDoS protected, no contracts, cancel anytime.

From $4.80 /month