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
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 Value | Server State | Player Experience |
|---|---|---|
| 20.0 | Healthy | Smooth gameplay, no lag |
| 18.0-19.0 | Minor lag | Occasional stutters |
| 15.0-17.0 | Moderate lag | Noticeable delays |
| <15.0 | Severe lag | Nearly unplayable |
How to check TPS:
# Paper/Spigot servers
/tps
# With spark plugin (recommended)
/spark tpsMSPT (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 Value | Status | What It Means |
|---|---|---|
| <40ms | Excellent | Server has headroom |
| 40-50ms | Good | Running at target |
| >50ms | Dropping ticks | Can't maintain 20 TPS |
| >100ms | Critical | Severe performance issues |
Check MSPT:
/mspt # Paper servers
/spark tps # Shows TPS, MSPT, and CPU usageThe 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 usage
/spark heapsummary
# Monitor GC activity
/spark gcCPU Usage
High CPU usage indicates computational bottlenecks—too many entities, complex redstone, or inefficient plugins.
/spark tps # Shows CPU percentageServer 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 (example for 1.21)
wget https://api.papermc.io/v2/projects/paper/versions/1.21/builds/latest/downloads/paper-1.21-latest.jarPros:
- 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 (example for 1.21)
wget https://api.purpurmc.org/v2/purpur/1.21/latest/downloadPros:
- 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:
# View distance - how far players can see
view-distance=8
# Simulation distance - how far the server processes entities/blocks
simulation-distance=4Recommended values:
| Server Type | View Distance | Simulation Distance |
|---|---|---|
| Budget/High player count | 5-6 | 3-4 |
| Mid-range | 7-8 | 4-5 |
| High-performance | 10+ | 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:
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: 32Why 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):
# Install Chunky plugin, then in-game:
/chunky world world
/chunky radius 5000
/chunky start
# Monitor progress
/chunky statusPre-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:
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 corespaper-world-defaults.yml:
# 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 86. Optimize Java Flags
Use Aikar's flags (recommended by most hosting providers):
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 --noguiReplace -Xms10G -Xmx10G with your available RAM. The Xms and Xmx values should match.
Additional Resources
For more optimization guides, check out:
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:
Essential 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 gcSpark 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:
- Look for the widest sections—these consume the most time
- Check if plugins appear disproportionately large
- Identify if vanilla operations (entities, chunks) dominate
- 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:
/spark tps
/spark heapsummaryRecord:
- 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:
| Test | Bot Count | Duration | Goal |
|---|---|---|---|
| 1 | 10 | 5 min | Verify test setup works |
| 2 | 25 | 10 min | Watch for early degradation |
| 3 | 50 | 15 min | Typical peak load for small servers |
| 4 | 100 | 15 min | Stress test for mid-size servers |
| 5 | 200+ | 15 min | Find breaking point |
During each test:
# Monitor every 60 seconds
/spark tps
/spark heapsummary
# Run a full profile for 120 seconds
/spark profiler start --timeout 120Record 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:
- Start with 10 bots connected
- Join 50 additional bots simultaneously
- Monitor TPS during the surge
- Wait 5 minutes for stabilization
- 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:
- Connect 50-75% of your target capacity
- Keep them connected for 4-8 hours
- Monitor memory usage trends
- 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:
/spark profiler start --timeout 300
# Wait for performance issues to occur
/spark profiler stopWhat to look for:
- Plugin names taking >10% of CPU: Investigate configuration or replace plugin
- Entity AI dominating: Reduce mob caps or entity ranges
- Chunk operations excessive: Adjust chunk loading settings
- 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
/spark heapsummaryLook 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
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 despawnBottleneck: Chunk Loading
Symptoms: TPS drops when players explore, chunk load errors
Solutions:
- Pregenerate more world
- Reduce view distance
- Increase chunk loading thread count:
# paper-global.yml
chunk-loading-advanced:
player-max-chunk-load-rate: 50.0 # Reduce from 100Bottleneck: Redstone Lag
Symptoms: Periodic TPS drops, Spark shows redstone ticking
Solutions:
- Use redstone limiters (plugins like RedstoneControl)
- Educate players on efficient designs
- Set chunk tick limits:
# paper-world-defaults.yml
max-auto-save-chunks-per-tick: 6Bottleneck: Plugin Overhead
Symptoms: Specific plugin shows in Spark profile
Solutions:
- Check plugin configuration for expensive features
- Update to latest version (may have optimizations)
- Consider alternatives with better performance
- Disable if not essential
Interpreting Test Results
After testing, you should be able to answer:
- Maximum safe capacity: How many players before TPS drops below 18?
- Comfortable capacity: How many players can you host at 20 TPS with headroom?
- Bottleneck identification: What limits your capacity (CPU, RAM, entities, plugins)?
- Spike tolerance: Can you handle sudden load increases?
- 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:
- Configure target server and bot count
- Set join delays to simulate realistic connection patterns (1-3 seconds between bots)
- Enable movement plugins (Anti-AFK, Auto-Jump) for realistic behavior
- Monitor server performance during bot connection phase
- Run test for 15-30 minutes to observe stability
Example 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:
#!/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:
- Optimize before testing: Don't test an unoptimized baseline
- Test incrementally: Start small, increase gradually
- Monitor comprehensively: Use Spark for detailed profiling
- Test realistically: Idle bots don't represent real players
- Document everything: Record metrics, configurations, and findings
- Test regularly: Make it part of your maintenance routine
- Test spikes: Sudden load increases reveal different issues than gradual scaling
- Consider network: Test from realistic network locations
- Account for growth: Target 70-80% of max capacity for safety margin
- 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:
- Optimize your baseline configuration
- Set up monitoring tools (Spark)
- Test incrementally with realistic behaviors
- Analyze results to find bottlenecks
- 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.