Skip to content
Bytearium

No ads or affiliate links active

Homelab & storage

Minecraft server lag: find the cause with spark

Minecraft server lag has four causes: slow ticks, spikes, network or client. Measure MSPT with spark, fix the biggest block first, upgrade last.

"It lags" is what players say the way patients say "it hurts": true, urgent and not yet a diagnosis. This guide turns the complaint into a number, and the number into one targeted change.

The short answer

Minecraft server lag means one of four different problems: ticks that take too long, rare lag spikes, a poor network path or a weak client. Only the first two are the server's job, and one number separates them from the rest: MSPT, the milliseconds the server needs for one tick. The server aims for 20 ticks per second, which leaves 50 ms per tick [1][2]. If your ticks fit into that budget, the complaint lies elsewhere. If they do not, spark, the profiler that Paper has bundled since version 1.21 [7], shows which part of the tick eats the time. Fix the biggest block first, measure again, and think about a bigger server last. Our assessment: more RAM does not shorten a tick that is waiting for the processor, and a spark report tells you whether that is your case [13][18][20].

How it works

  1. Ticks, TPS and MSPT. Minecraft runs on a loop, and every pass is a tick. In one tick the server handles player packets, moves entities, spawns and steers mobs, processes redstone and sends updates to players [1]. It tries to run exactly 20 ticks per second, one every 50 milliseconds. When a tick finishes early, the server sleeps for the rest of the 50 ms. When a tick runs long, the next one starts late, because ticks cannot run in parallel, and the whole game slows down [1]. TPS (ticks per second) counts how many ticks were completed in a second. MSPT (milliseconds per tick) says how long a tick took. For 20 TPS the average has to stay at or below 50 ms [2]. spark also reports the minimum, the median, the 95th percentile and the maximum, and colours values green, amber or red [2]. In our view MSPT is the better early warning, because TPS stays at 20 as long as the average fits into the budget and only drops once the reserve is gone [2][20].
  2. Read the numbers. /spark tps prints the TPS rate and CPU usage, and spark's guide explains TPS and MSPT together [2][3]. Paper's own /tps shows the last 1, 5 and 15 minutes, and /mspt shows average, minimum and maximum of the last 5, 10 and 60 seconds, but the Paper documentation calls both superseded by spark [8]. On a vanilla server, /tick query (since 1.20.3, permission level 3) prints the ticking status, the average time per tick and percentiles [17]. In the server console you type commands without the leading slash [21]. In game you may need to be an operator or hold the spark permission [6].
  3. Headroom. In a spark profile the tick loop sits near the top, and the time the server spends sleeping is your reserve. spark's guide calls a high sleep share healthy, says that below 20 percent sleep the server works hard and below 5 percent it probably lags with no spare capacity, and reminds you that all of these values are averages [1].
  4. Profile while the lag happens. Paper's documentation stresses that the problem must be actively occurring, otherwise the profile shows a healthy server [7]. Run /spark profiler start --timeout 600. After ten minutes spark returns a link to the report [7]. /spark profiler info shows the status, open views a running profile, stop ends it now, and cancel drops it without uploading [3]. The viewer link can be shared freely [5], so treat it as public. If you would rather keep the data local, /spark profiler stop --save-to-file saves the profile under the config directory instead of uploading it [3]. Paper 1.21 and newer include spark. On older versions you install the plugin jar, and a newer standalone jar can replace the bundled one if you add -Dpaper.preferSparkPlugin=true to the startup arguments [6][7]. Paper's Timings profiler is deprecated and off by default since 1.21 [7].
  5. Read the report. Open the "Server thread" first, the main thread that runs the game [5]. Every line shows the share of the thread's time. Expand the biggest child, then its biggest child, and "follow the numbers" [5]. The viewer also offers a flat view with the 250 slowest method calls, a sources view with one tree per plugin or mod, and a flame graph in which width means time [5]. Because the game's own method names are scrambled, the viewer applies deobfuscation mappings automatically and lets you pick them by hand if that fails [5]. In our reading, three families of names deserve your first look: entities, chunk loading and plugin names.
  6. Spikes need a different tool. An averaged profile hides rare long ticks, because the normal ticks cancel the spike out [4]. First run /spark tickmonitor. It reports ticks that took much longer than the average (by default twice as long), and --threshold-tick 50 reports every tick above 50 ms [3][4]. Then profile only the long ticks with /spark profiler start --only-ticks-over 100. spark suggests a threshold between 50 and 100 that stays below the length of the laggy ticks you saw [3][4]. Match each tickmonitor message to what happened in game at that moment [4].

Which kind of lag do you have?

This table is our assessment, built from the sources above.

What players reportLikely kindFirst check
Everything slows down: mobs, redstone, blocks snap backTick lag/spark tps, MSPT above 50 ms
Short freezes every few seconds or minutesLag spikes/spark tickmonitor, then --only-ticks-over
Actions arrive late, but mobs and redstone run at normal speedNetwork path/spark ping, compare with MSPT [3]
One player stutters, everyone else is fineThat player's client or connection/spark ping --player NAME [3], ask for frame rate

If TPS sits at 20, MSPT stays well under 50 and the sleep share is high, stop changing the server. The problem is not the tick.

What to change, in this order

Change one thing at a time and measure again under similar load. The order is our judgement, from cheap and safe to invasive, not a measured ranking.

  1. Chunk generation. When players explore, the server has to generate terrain on the spot, and that shows up as spikes. Chunky generates the area in advance. Its documented commands are chunky world NAME, chunky center X Z or chunky spawn, chunky radius 5000, chunky start, and then chunky progress, chunky pause and chunky continue [14]. chunky worldborder copies the vanilla world border, and the vanilla /worldborder set takes the full width, so a border of 10000 matches a Chunky radius of 5000 [14][21]. The world name depends on your setup, for example world or overworld for the Overworld [15]. Hangar lists Chunky 1.5.3 for 26.1 to 26.3 [16]. Run it while the server is empty, because pre-generation is the same heavy work players trigger, only all at once [21]. It costs disk space and backup time, so start with a modest radius [21].
  2. Distances. simulation-distance is the radius in chunks in which the server updates living entities. view-distance is how much world data is sent to clients. Both default to 10, with a range of 3 to 32 [9]. Lowering the simulation distance reduces the work the server does in each tick, and it is the setting we would try first [20]. Lower it by one or two steps, not to the floor. We found no official recommended value, so treat any number from a forum or a third-party guide as a test value.
  3. Entities. /paper entity list lists the currently ticking entities, and you can filter by type such as minecraft:pig [8]. Spawn limits live in bukkit.yml (monsters 70 by default) and can be overridden per world [11]. per-player-mob-spawns spreads the mob cap per player [10]. In spigot.yml, entity-activation-range decides how far from a player entities tick normally: 32 blocks for animals and monsters, 64 for raiders, 16 for miscellaneous entities by default [12]. Careful: Paper notes that a small range for miscellaneous entities can make items in water streams look laggy or move backward [12]. Third-party guides name large mob farms, dense villager halls and constant hopper activity as common candidates [20], and your profile shows whether yours is one.
  4. Plugins. The sources view shows the share of time per plugin [5]. Update it, change its configuration, replace it or drop it.
  5. Autosave. Paper's max-auto-save-chunks-per-tick defaults to 24 [10]. If your spikes arrive on a regular beat, look at tickmonitor timestamps and at the profile of those ticks before you touch it. We have not tested this setting.
  6. Memory and garbage collection. Java frees unused memory in sweeps called garbage collection (GC), and a long sweep freezes a tick. /spark gc prints the GC history, /spark gcmonitor reports GC activity as it happens, and /spark health show --memory adds JVM memory details [3]. Paper's page on startup flags recommends at least 6 to 10 GB, tells you to set the heap about 1000 to 1500 MB below the memory your host gives you, and warns that more memory stops paying off at some point [13]. Other sources give smaller figures for small servers, so check [18] against your own report. All of them agree that more is not automatically better.

When a bigger server helps

A bigger machine is the right answer when the report says the processor is the limit, and only then. The signs, in our reading: the server thread has almost no sleep time, and no single plugin, entity group or chunk source stands out any more after the steps above. Then buy for single-core speed. The Minecraft Wiki says a server mostly uses one core and recommends a CPU with high single-thread performance [18]. Extra cores help plugins and some background work, but the core mechanics such as ticking largely stay on one thread [19]. RAM is a different matter: setupmc.com puts it plainly, more RAM does not shorten CPU-bound tick work [20]. On rented servers, check whether CPU and RAM are guaranteed or shared, because the Wiki lists that as a point to compare [18]. Our guides on hosting criteria, on running a Minecraft server on a VPS and on running one at home cover the buying side.

A worked example (invented values for practice, not a measurement)

Six friends play on a Paper server, and every evening someone says "it lags". During the evening you run:

/spark tps
/spark profiler start --timeout 600

Reading A: MSPT averages 22 ms, the 95th percentile is 38 ms, the sleep share in the profile is high. The tick is fine. Check /spark ping, the players' connections and their frame rates before you touch any setting.

Reading B: MSPT averages 58 ms, the sleep share is below 5 percent, and 45 percent of the server thread sits under chunk loading while two friends fly in different directions. Pre-generate with Chunky, shrink the explored area with a border, measure again.

Reading C: MSPT averages 61 ms, sleep is below 5 percent, and after the steps above nothing stands out any more. The server thread is the limit. Now a processor with stronger single-core speed is a justified purchase, and no RAM upgrade will fix it.

After each change, run the same profile again and write both results next to each other. A change that does not move the number goes back.

Checklist

  • Measure /spark tps while the lag is happening, and note MSPT, the 95th percentile and CPU usage.
  • Separate tick lag, lag spikes, network and client before you change anything.
  • Start /spark profiler start --timeout 600 during the problem, and open the Server thread first.
  • Check the sleep share: below 20 percent means the server works hard, below 5 percent means no reserve.
  • Run /spark tickmonitor and --only-ticks-over for spikes instead of averaged profiles.
  • Pre-generate explored terrain with Chunky while the server is empty, and set a border first.
  • Lower simulation-distance before view-distance, and change one value at a time.
  • Look at the sources view before you blame the server, because one plugin can cost most of the tick.
  • Compare two reports under similar load, and revert a change that did not help.
  • Buy a faster single core, not more RAM, only when the report shows the processor as the limit.

Primary sources

These sources are the basis of this page. That does not mean every claim was checked individually; whether a review record exists is shown above under “Status”. The interpretation and checklist are our own work.

There is no documented review record for this version yet. The text relies on the sources listed.

How this page was made: Bytearium creates these pages with the help of AI and is responsible for publishing them. AI can be wrong, so we show our sources and review status openly.

  1. spark projectThe Tick Loop
  2. spark projectTPS and MSPT
  3. spark projectCommand Usage
  4. spark projectFinding the cause of lag spikes
  5. spark projectUsing the viewer
  6. spark projectInstallation
  7. PaperMCProfiling
  8. PaperMCCommands
  9. PaperMCserver.properties
  10. PaperMCWorld configuration
  11. PaperMCbukkit.yml
  12. PaperMCspigot.yml
  13. PaperMCAikar's flags
  14. Chunky projectCommands
  15. Chunky projectPregeneration
  16. PaperMC HangarChunky
  17. Minecraft Wiki/tick
  18. Minecraft WikiTutorial: Setting up a Java Edition server
  19. Minecraft WikiServer/Requirements
  20. setupmc.comInvestigate Minecraft lag: TPS, MSPT, and "Can't keep up"
  21. arrowtan.storeChunky and spark: Pregenerate Your World and Find Server Lag

This page has no ads and no affiliate links.