SoulFire v2 is out now!
Back to Blog
By Pistonmaster

Stress Testing Minecraft Servers - A Complete Guide

Learn how to properly stress test your Minecraft server, measure performance metrics, identify bottlenecks, and optimize for peak player loads

minecraftstress-testingperformanceoptimizationtpsmspt

Understanding Server Stress Testing

Stress testing is the practice of simulating high player loads on your Minecraft server to evaluate how it performs under pressure. Whether you're launching a new server, deploying a major update, or scaling your infrastructure, stress testing helps you identify performance bottlenecks before they impact real players.

The goal isn't just to see when your server crashes—it's to understand how it degrades under load, where the bottlenecks are, and what capacity you can reliably support.

Why Stress Testing Matters

Without stress testing, you're essentially gambling with your players' experience. Here's what proper testing prevents:

  • Launch day disasters: Your new server opens, 200 players join simultaneously, and TPS drops to 5
  • Update surprises: A new plugin seems fine with 10 players but causes severe lag with 50
  • Hardware uncertainty: You don't know if that VPS upgrade was worth it
  • Plugin conflicts: Multiple plugins work individually but compete for resources under load

Key Performance Metrics

Before stress testing, you need to understand what you're measuring. Minecraft servers have specific performance indicators that reveal different aspects of server health.

TPS (Ticks Per Second)

Minecraft runs on a tick-based system, targeting 20 ticks per second (one tick every 50ms). TPS is the single most important metric for server performance.

TPS ValueServer StatePlayer Experience
20.0HealthySmooth gameplay, no lag
18.0-19.0Minor lagOccasional stutters
15.0-17.0Moderate lagNoticeable delays
<15.0Severe lagNearly unplayable

How to check TPS:

Check TPS commands
# Paper/Spigot servers
/tps

# With spark plugin (recommended)
/spark tps

MSPT (Milliseconds Per Tick)

MSPT measures how long the server takes to process each tick. This is often more revealing than TPS because it shows performance trends before TPS drops.

MSPT ValueStatusWhat It Means
<40msExcellentServer has headroom
40-50msGoodRunning at target
>50msDropping ticksCan't maintain 20 TPS
>100msCriticalSevere performance issues

Check MSPT:

Check MSPT commands
/mspt  # Paper servers

/spark tps  # Shows TPS, MSPT, and CPU usage

The spark output shows three values: current MSPT, median MSPT (over 10 seconds), and 95th percentile. The 95th percentile is crucial—it shows your worst-case performance excluding outliers.

Memory Usage

Monitor both heap memory and GC (garbage collection) activity. Frequent GC pauses can cause lag spikes even when average TPS looks healthy.

Check memory and GC
# Check memory usage
/spark heapsummary

# Monitor GC activity
/spark gc

CPU Usage

High CPU usage indicates computational bottlenecks—too many entities, complex redstone, or inefficient plugins.

Check CPU usage
/spark tps  # Shows CPU percentage

Server Optimization Fundamentals

Optimize Before Testing

Before stress testing, optimize your baseline configuration. Testing an unoptimized server wastes time—you'll just discover it needs optimization. Always establish a solid performance foundation first.

1. Choose the Right Server Software

Paper is the gold standard for performance. It includes hundreds of optimizations over Spigot while maintaining plugin compatibility.

Best all-around choice for most servers. Excellent plugin compatibility with significant performance improvements over Spigot.

Download Paper server
# Download Paper (example for 1.21)
wget https://api.papermc.io/v2/projects/paper/versions/1.21/builds/latest/downloads/paper-1.21-latest.jar

Pros:

  • Hundreds of performance optimizations
  • Full Spigot plugin compatibility
  • Active development and updates
  • Excellent community support

Paper fork with additional gameplay features and further optimizations. Ideal if you want extra configuration options.

Download Purpur server
# Download Purpur (example for 1.21)
wget https://api.purpurmc.org/v2/purpur/1.21/latest/download

Pros:

  • All Paper optimizations included
  • Additional configuration options
  • Extra gameplay features
  • Performance tweaks for specific scenarios

Paper fork specifically optimized for large player counts. Best for servers expecting 100+ concurrent players.

Pros:

  • Optimized for high player counts
  • Additional async operations
  • Entity activation range improvements
  • Better mob spawning algorithms

Experimental multi-threaded Paper fork. Only for specific use cases with multiple isolated worlds.

Pros:

  • Multi-threaded world ticking
  • Potential for massive player counts

Cons:

  • Limited plugin compatibility
  • Experimental and unstable
  • Not suitable for most servers

Avoid Legacy Software

Avoid Bukkit and CraftBukkit—they're severely outdated in terms of performance and lack modern optimizations.

2. Configure View and Simulation Distance

These are the most impactful performance settings you'll adjust.

server.properties:

server.properties
# View distance - how far players can see
view-distance=8

# Simulation distance - how far the server processes entities/blocks
simulation-distance=4

Recommended values:

Server TypeView DistanceSimulation Distance
Budget/High player count5-63-4
Mid-range7-84-5
High-performance10+6-8

Why simulation distance matters more: Every chunk within simulation distance requires entity processing, crop growth, redstone ticking, and more. This is far more expensive than simply rendering chunks.

Setting simulation distance lower than view distance is the secret weapon—players get good visibility without the processing overhead.

3. Optimize Entity Limits

paper-world-defaults.yml:

paper-world-defaults.yml
entities:
  spawning:
    # Spawn limits per player (prevents farm exploitation)
    spawn-limits:
      monster: 20
      creature: 5
      water_creature: 2
      water_ambient: 2
      water_underground_creature: 3
      axolotl: 3
      ambient: 1

  # How often mobs spawn (higher = less frequent)
  ticks-per-spawn:
    monster: 10
    creature: 400
    water_creature: 400
    water_ambient: 400
    axolotl: 400
    ambient: 400

entities-target-range:
  # Reduce AI range for mobs
  monsters: 32
  creatures: 32

Why this matters: Mob AI is expensive. Limiting spawn counts and reducing their targeting range significantly improves performance.

4. Pregene rate Chunks

Chunk generation is extremely expensive. Generate your world before players explore it.

Using Chunky (recommended):

Pregenerate chunks with Chunky
# Install Chunky plugin, then in-game:
/chunky world world
/chunky radius 5000
/chunky start

# Monitor progress
/chunky status

Pre-generation benefits:

  • Eliminates real-time generation lag (TPS drops from 20 to 2-8 during exploration)
  • Prevents chunk loading errors and stuttering
  • Catches world generation bugs before players encounter them
  • Dramatically improves launch day experience

Pro tip: Pre-generate during off-peak hours or on a separate test server. The generation process itself causes significant lag.

Performance Warning

Chunk generation during pregeneration will cause severe lag. Never pregenerate while players are online. Run this process overnight or on a separate test server, then copy the world files to your production server.

5. Configure Paper's Advanced Settings

paper-global.yml:

paper-global.yml
chunk-loading-advanced:
  # Prevent massive lag from chunk loading
  player-max-chunk-load-rate: 100.0

packet-limiter:
  # Protect against packet flooding
  kick-message: '&cSent too many packets'
  limits:
    all:
      interval: 7.0
      max-packet-rate: 500.0

async-chunks:
  # Load chunks off main thread
  threads: -1  # Auto-detect CPU cores

paper-world-defaults.yml:

paper-world-defaults.yml - Additional settings
# Use per-player mob spawning (like singleplayer)
spawn-limits:
  spawn-mechanism: per-player  # Much better than "bukkit"

# Reduce entity collision checks
entities:
  behavior:
    max-entity-collisions: 2  # Down from 8

6. Optimize Java Flags

Use Aikar's flags (recommended by most hosting providers):

Aikar's Java flags for optimal performance
java -Xms10G -Xmx10G -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 paper.jar --nogui

Replace -Xms10G -Xmx10G with your available RAM. The Xms and Xmx values should match.

Additional Resources

Setting Up Performance Monitoring

Before stress testing, set up monitoring tools so you can analyze what happens under load.

Install Spark

Spark is the best Minecraft profiler available. It works on Paper, Spigot, Fabric, Forge, and proxies.

Installation:

  1. Download from SpigotMC or Modrinth
  2. Place spark.jar in your plugins/ folder
  3. Restart the server

Essential commands:

Essential Spark commands
# Quick health check
/spark tps

# Start a 60-second CPU profiler
/spark profiler start

# Stop and generate report
/spark profiler stop

# Generate heap dump
/spark heapsummary

# Monitor GC activity
/spark gc

Spark generates web-based reports you can share with others for analysis.

Understanding Spark Profiles

When you run /spark profiler, it creates a flamegraph showing where server time is spent:

  • Red zones: Main thread operations (world ticking, entity processing)
  • Plugin names: Show which plugins are consuming CPU
  • Method names: Reveal exactly which operations are slow

How to read a profile:

  1. Look for the widest sections—these consume the most time
  2. Check if plugins appear disproportionately large
  3. Identify if vanilla operations (entities, chunks) dominate
  4. Compare before/after profiles when making changes

Conducting a Stress Test

Now you're ready to stress test. Here's a methodical approach.

Phase 1: Establish Baseline (0 Load)

Start with an empty server and record idle performance:

Establish baseline performance
/spark tps
/spark heapsummary

Record:

  • Idle TPS (should be 20.0)
  • Idle MSPT (should be <10ms)
  • Base memory usage
  • CPU usage

This baseline helps identify when load causes degradation.

Phase 2: Gradual Load Testing

Don't immediately test with 500 bots—you'll learn nothing except "it crashes." Test incrementally:

Test progression:

TestBot CountDurationGoal
1105 minVerify test setup works
22510 minWatch for early degradation
35015 minTypical peak load for small servers
410015 minStress test for mid-size servers
5200+15 minFind breaking point

During each test:

Monitor during load testing
# Monitor every 60 seconds
/spark tps
/spark heapsummary

# Run a full profile for 120 seconds
/spark profiler start --timeout 120

Record these metrics:

  • Average TPS over test duration
  • MSPT (current, median, 95th percentile)
  • Memory usage trends
  • Any error messages or warnings
  • Player join success rate
  • Time to join (connection speed)

Phase 3: Behavioral Testing

Idle bots don't represent real players. Add realistic behaviors:

What it tests: Entity tracking, pathfinding, collision detection, chunk loading from player movement

How to set up: Configure bots to walk randomly or follow waypoints

Expected impact: Moderate CPU usage, tests entity tracking systems

What to monitor:

  • EntityAI CPU usage in Spark
  • Chunk loading frequency
  • Network packet rates

What it tests: World I/O, chunk generation (if not pregenerated), async chunk loading

How to set up: Bots flying or rapidly moving to unexplored areas

Expected impact: High disk I/O, potential TPS drops if chunks aren't pregenerated

What to monitor:

  • Chunk generation time in Spark
  • Disk I/O metrics
  • TPS during exploration

What it tests: Mob AI, damage calculations, entity death/spawn cycles

How to set up: Bots attacking nearby mobs or each other (PvP)

Expected impact: High entity AI usage, frequent entity state changes

What to monitor:

  • EntityAI percentage in profiles
  • Mob spawn/despawn rates
  • Server tick time during combat

What it tests: Block updates, redstone ticking, chunk ticking

How to set up: Build test redstone contraptions, have bots activate them

Expected impact: Periodic TPS drops, high block update rates

What to monitor:

  • Redstone ticking in Spark
  • Block update frequency
  • Chunk tick time

Most bot tools support basic movement patterns. Even simple random walking provides valuable data.

Phase 4: Spike Testing

Real servers experience sudden load spikes—100 players join within 30 seconds during events.

Spike test procedure:

  1. Start with 10 bots connected
  2. Join 50 additional bots simultaneously
  3. Monitor TPS during the surge
  4. Wait 5 minutes for stabilization
  5. Check if TPS recovers to baseline

What to watch:

  • Does TPS drop below 15 during the spike?
  • How long until TPS stabilizes?
  • Do any plugins throw errors?
  • Does chunk loading keep up?

Phase 5: Endurance Testing

Some issues only appear after hours of runtime—memory leaks, gradual resource exhaustion.

Endurance test:

  1. Connect 50-75% of your target capacity
  2. Keep them connected for 4-8 hours
  3. Monitor memory usage trends
  4. Watch for gradual TPS degradation

Signs of problems:

  • Memory usage climbing steadily (memory leak)
  • Gradually increasing MSPT (resource exhaustion)
  • More frequent GC pauses over time

Analyzing Results and Identifying Bottlenecks

After testing, analyze your data to find bottlenecks.

TPS Degradation Patterns

Pattern: TPS drops proportionally with player count

  • Cause: General overhead (entities, chunks, networking)
  • Solution: Optimize view/simulation distance, reduce entity caps

Pattern: TPS spikes down randomly

  • Cause: Chunk generation, large redstone devices, or plugin tasks
  • Solution: Pregenerate chunks, limit redstone, profile with Spark

Pattern: TPS stable but MSPT creeping up

  • Cause: Gradual resource exhaustion or memory pressure
  • Solution: Check for memory leaks, optimize GC, review plugin efficiency

Pattern: Good TPS but high CPU usage (>80%)

  • Cause: CPU bottleneck—limited headroom for spikes
  • Solution: Optimize further or upgrade CPU

Reading Spark Profiles

Generate a profile during degraded performance:

Generate performance profile during degradation
/spark profiler start --timeout 300
# Wait for performance issues to occur
/spark profiler stop

What to look for:

  1. Plugin names taking >10% of CPU: Investigate configuration or replace plugin
  2. Entity AI dominating: Reduce mob caps or entity ranges
  3. Chunk operations excessive: Adjust chunk loading settings
  4. Redstone ticking consuming time: Limit redstone contraptions

Example findings:

EntityAI: 35% (too high - reduce mob counts)
ChunkGeneration: 20% (pregenerate more)
PluginX: 15% (check if necessary, optimize config)
WorldTick: 20% (normal)
NetworkManager: 10% (normal)

Memory Analysis

Analyze memory usage
/spark heapsummary

Look for:

  • High memory usage (>85%): Risk of GC thrashing
  • Unusual object counts: Potential memory leaks
  • Chunk data dominating: May need to reduce view distance

Common Bottlenecks and Solutions

Bottleneck: Entity Overload

Symptoms: High MSPT, Spark shows EntityAI using >30% CPU

Solutions:

paper-world-defaults.yml - Reduce entity load
# paper-world-defaults.yml
entities:
  spawning:
    spawn-limits:
      monster: 15  # Reduce from 20
      creature: 3  # Reduce from 5

  # Increase despawn distance
  despawn-ranges:
    monster:
      soft: 28  # Start despawning
      hard: 96  # Force despawn

Bottleneck: Chunk Loading

Symptoms: TPS drops when players explore, chunk load errors

Solutions:

  1. Pregenerate more world
  2. Reduce view distance
  3. Increase chunk loading thread count:
paper-global.yml - Reduce chunk loading rate
# paper-global.yml
chunk-loading-advanced:
  player-max-chunk-load-rate: 50.0  # Reduce from 100

Bottleneck: Redstone Lag

Symptoms: Periodic TPS drops, Spark shows redstone ticking

Solutions:

  1. Use redstone limiters (plugins like RedstoneControl)
  2. Educate players on efficient designs
  3. Set chunk tick limits:
paper-world-defaults.yml - Limit chunk ticking
# paper-world-defaults.yml
max-auto-save-chunks-per-tick: 6

Bottleneck: Plugin Overhead

Symptoms: Specific plugin shows in Spark profile

Solutions:

  1. Check plugin configuration for expensive features
  2. Update to latest version (may have optimizations)
  3. Consider alternatives with better performance
  4. Disable if not essential

Interpreting Test Results

After testing, you should be able to answer:

  1. Maximum safe capacity: How many players before TPS drops below 18?
  2. Comfortable capacity: How many players can you host at 20 TPS with headroom?
  3. Bottleneck identification: What limits your capacity (CPU, RAM, entities, plugins)?
  4. Spike tolerance: Can you handle sudden load increases?
  5. Stability over time: Does performance degrade during long sessions?

Example results interpretation:

Baseline: 20 TPS, 5ms MSPT, 30% CPU
50 players: 20 TPS, 35ms MSPT, 60% CPU ✅ Good
100 players: 19 TPS, 48ms MSPT, 85% CPU ⚠️ Near limit
150 players: 16 TPS, 65ms MSPT, 95% CPU ❌ Over capacity

Conclusion: Comfortable capacity = 75 players
            Maximum capacity = 100 players
            Bottleneck: CPU (85%+ at capacity)

Using Bots for Stress Testing

While manual testing with real players provides the most accurate results, it's impractical for most testing scenarios. Automated bot tools let you run repeatable tests on demand.

What to Look For in Bot Tools

When selecting a bot solution for stress testing:

Essential features:

  • Multiple bot support (100+ simultaneous connections)
  • Connection control (join delays, staggered spawning)
  • Basic movement (walking, looking around)
  • Protocol compliance (proper packet handling)
  • Proxy support (for realistic network paths)
  • Resource efficiency (bots shouldn't consume excessive host resources)

Nice-to-have features:

  • Action simulation (breaking blocks, attacking, chatting)
  • API/CLI for automation
  • Metrics reporting
  • Multi-version support

Testing with SoulFire

SoulFire is a Fabric-based bot tool that addresses many limitations of traditional bot frameworks. Because it runs the actual Minecraft client code, bots behave identically to real players from the server's perspective—critical for accurate stress testing.

Why this matters for testing:

Traditional bot frameworks (like Mineflayer) reimplement Minecraft's protocol and physics. This can lead to:

  • Different packet timing than real clients
  • Inaccurate physics calculations
  • Missed edge cases in newer protocol versions
  • Detectable patterns that real players wouldn't exhibit

SoulFire's Fabric architecture means:

  • Perfect protocol parity: Packets match real clients exactly
  • Accurate physics: Movement, collisions identical to real players
  • Reliable multi-version support: Via ViaFabricPlus, test any Minecraft version
  • Realistic resource usage: Server load matches real player patterns

Basic stress test setup:

  1. Configure target server and bot count
  2. Set join delays to simulate realistic connection patterns (1-3 seconds between bots)
  3. Enable movement plugins (Anti-AFK, Auto-Jump) for realistic behavior
  4. Monitor server performance during bot connection phase
  5. Run test for 15-30 minutes to observe stability

Example test configuration:

Example SoulFire test configuration
Address: your-server.com:25565
Bot Amount: 100
Min Join Delay: 1000ms
Max Join Delay: 3000ms
Protocol Version: 1.21

Enabled Plugins:
- Auto Respawn
- Anti AFK (random movement)
- Auto Jump (simulates player activity)
- Chat Logger (monitor server messages)

The goal is simulating realistic player behavior patterns while collecting server performance data. Even basic movement is enough to stress entity tracking, chunk loading, and network processing.

Continuous Testing Strategy

Don't just test once—integrate stress testing into your development workflow.

When to Stress Test

  • Before launch: Validate capacity claims
  • After major updates: Ensure new plugins don't degrade performance
  • Before events: Verify you can handle expected turnout
  • After hardware changes: Confirm improvements delivered value
  • Monthly: Catch gradual degradation (memory leaks, accumulating data)

Automated Testing

Set up recurring tests:

weekly-stress-test.sh
#!/bin/bash
# weekly-stress-test.sh

echo "Starting weekly stress test..."

# Start bots (using your chosen tool)
start_bots 50

# Wait 15 minutes
sleep 900

# Collect metrics
rcon-cli "spark profiler stop" > /var/log/minecraft/stress-test-$(date +%Y%m%d).log
rcon-cli "spark tps" >> /var/log/minecraft/stress-test-$(date +%Y%m%d).log

# Stop bots
stop_bots

echo "Stress test complete. Check /var/log/minecraft/ for results."

Best Practices Summary

Testing Best Practices

Follow these essential guidelines for effective stress testing:

  1. Optimize before testing: Don't test an unoptimized baseline
  2. Test incrementally: Start small, increase gradually
  3. Monitor comprehensively: Use Spark for detailed profiling
  4. Test realistically: Idle bots don't represent real players
  5. Document everything: Record metrics, configurations, and findings
  6. Test regularly: Make it part of your maintenance routine
  7. Test spikes: Sudden load increases reveal different issues than gradual scaling
  8. Consider network: Test from realistic network locations
  9. Account for growth: Target 70-80% of max capacity for safety margin
  10. Share results: Use Spark profiles to collaborate on optimization

Conclusion

Stress testing isn't about finding the exact moment your server crashes—it's about understanding how it performs under various loads, identifying bottlenecks, and optimizing before players experience problems.

The methodology is straightforward:

  1. Optimize your baseline configuration
  2. Set up monitoring tools (Spark)
  3. Test incrementally with realistic behaviors
  4. Analyze results to find bottlenecks
  5. Optimize and retest

By following this guide, you'll launch with confidence, knowing exactly what your server can handle and where its limits are. Your players will thank you with smooth, lag-free gameplay—even during peak hours.

Remember: The best stress test is the one you run before your players do it for you.