Server performance is crucial for maintaining a healthy FiveM community. Poor performance leads to player frustration, increased disconnections, and ultimately, server abandonment. This guide covers comprehensive optimization strategies to keep your server running smoothly.
⚠️ Warning: Poor server performance can cause significant player churn. Studies show that servers with FPS drops below 30 experience 40% higher player disconnection rates.
Table of Contents
1. Server Resources and Hardware
Recommended Server Specifications
Small Server (16-32 players)
- • CPU: 4-6 cores @ 3.0+ GHz
- • RAM: 8-16 GB DDR4
- • Storage: SSD 100+ GB
- • Network: 1 Gbps connection
Large Server (64+ players)
- • CPU: 8-12 cores @ 3.5+ GHz
- • RAM: 32-64 GB DDR4
- • Storage: NVMe SSD 500+ GB
- • Network: 10 Gbps connection
Operating System Optimization
# Linux server optimization (Ubuntu/Debian) # Update system packages sudo apt update && sudo apt upgrade -y # Install performance monitoring tools sudo apt install htop iotop nethogs -y # Configure kernel parameters for better performance echo 'net.core.rmem_max = 134217728' | sudo tee -a /etc/sysctl.conf echo 'net.core.wmem_max = 134217728' | sudo tee -a /etc/sysctl.conf echo 'net.ipv4.tcp_rmem = 4096 87380 134217728' | sudo tee -a /etc/sysctl.conf echo 'net.ipv4.tcp_wmem = 4096 65536 134217728' | sudo tee -a /etc/sysctl.conf # Apply changes sudo sysctl -p
2. Script Optimization Techniques
Thread Optimization
❌ Bad Practice: Using Citizen.Wait(0) in server scripts causes unnecessary CPU usage.
✅ Good Practice: Use appropriate wait times based on the operation frequency needed.
-- ❌ Inefficient server script
Citizen.CreateThread(function()
while true do
-- Heavy operation running every frame
ProcessAllPlayers()
Citizen.Wait(0) -- Too frequent for server
end
end)
-- ✅ Optimized server script
Citizen.CreateThread(function()
while true do
-- Process players every 5 seconds
ProcessAllPlayers()
Citizen.Wait(5000) -- Appropriate interval
end
end)
-- ✅ Client UI script (can use Wait(0))
Citizen.CreateThread(function()
while true do
-- Update UI elements
DrawHUD()
Citizen.Wait(0) -- OK for client UI
end
end)Event Optimization
-- ❌ Inefficient event handling
RegisterNetEvent('updatePlayerPosition')
AddEventHandler('updatePlayerPosition', function(x, y, z)
-- Update database every position change
MySQL.Async.execute('UPDATE players SET x=@x, y=@y, z=@z WHERE id=@id', {
['@x'] = x, ['@y'] = y, ['@z'] = z, ['@id'] = source
})
end)
-- ✅ Optimized with batching
local positionCache = {}
local lastSave = {}
RegisterNetEvent('updatePlayerPosition')
AddEventHandler('updatePlayerPosition', function(x, y, z)
local playerId = source
positionCache[playerId] = {x = x, y = y, z = z}
lastSave[playerId] = GetGameTimer()
end)
-- Save positions every 30 seconds
Citizen.CreateThread(function()
while true do
Citizen.Wait(30000)
for playerId, pos in pairs(positionCache) do
if GetGameTimer() - lastSave[playerId] > 30000 then
MySQL.Async.execute('UPDATE players SET x=@x, y=@y, z=@z WHERE id=@id', {
['@x'] = pos.x, ['@y'] = pos.y, ['@z'] = pos.z, ['@id'] = playerId
})
positionCache[playerId] = nil
end
end
end
end)Memory Management
- Use local variables: Always use
localfor variables to avoid global scope pollution - Clean up resources: Remove unused tables and variables when no longer needed
- Avoid memory leaks: Properly clean up event handlers and threads
- Limit cache sizes: Implement cache expiration for large data structures
-- Memory-efficient player data management
local PlayerData = {}
-- Clean up disconnected players
AddEventHandler('playerDropped', function()
local playerId = source
if PlayerData[playerId] then
-- Save data before cleanup
SavePlayerData(playerId)
PlayerData[playerId] = nil
end
end)
-- Periodic cleanup of unused data
Citizen.CreateThread(function()
while true do
Citizen.Wait(300000) -- 5 minutes
for playerId, data in pairs(PlayerData) do
if not GetPlayerPing(playerId) then
-- Player is no longer connected
PlayerData[playerId] = nil
end
end
end
end)3. Database Performance
MySQL Optimization
-- MySQL configuration optimization [mysqld] # Performance settings innodb_buffer_pool_size = 2G innodb_log_file_size = 256M innodb_flush_log_at_trx_commit = 2 query_cache_size = 64M query_cache_type = 1 max_connections = 200 thread_cache_size = 16 table_open_cache = 4000 # Connection settings wait_timeout = 28800 interactive_timeout = 28800 max_allowed_packet = 64M
Query Optimization
❌ Slow Query: SELECT * FROM players WHERE name LIKE '%john%' - No index on name column.
✅ Optimized Query: SELECT id, name, money FROM players WHERE identifier = 'steam:123' - Uses primary key index.
-- Efficient database operations
local function GetPlayerData(identifier)
-- Use prepared statements for better performance
local result = MySQL.Sync.fetchAll(
'SELECT id, name, money, level FROM players WHERE identifier = @identifier LIMIT 1',
{ ['@identifier'] = identifier }
)
return result[1]
end
-- Batch operations for better performance
local function UpdateMultiplePlayers(playerData)
local queries = {}
for playerId, data in pairs(playerData) do
table.insert(queries, {
query = 'UPDATE players SET money = @money WHERE id = @id',
values = { ['@money'] = data.money, ['@id'] = playerId }
})
end
-- Execute all updates in a single transaction
MySQL.Async.transaction(queries, function(result)
print("Updated " .. #queries .. " players")
end)
endConnection Pooling
-- oxmysql configuration with connection pooling
-- config.lua
Config.Database = {
connectionLimit = 10,
queueTimeout = 5000,
acquireTimeout = 60000,
timeout = 60000
}
-- Usage with connection pooling
local function SafeDatabaseOperation(callback)
MySQL.ready(function()
callback()
end)
end
-- Example usage
SafeDatabaseOperation(function()
local result = MySQL.Sync.fetchAll('SELECT * FROM players')
-- Process result
end)4. Resource Management
Resource Loading Order
-- server.cfg - Optimal resource loading order # Core resources (load first) ensure mapmanager ensure chat ensure spawnmanager ensure sessionmanager ensure basic-gamemode ensure hardcap ensure rconlog # Database and essential systems ensure oxmysql ensure es_extended # or your framework # Utility resources ensure adminmenu ensure scoreboard # Gameplay resources (load last) ensure vehicle-system ensure job-system ensure inventory-system
Resource Monitoring
-- Resource performance monitoring script
local resourceStats = {}
local function MonitorResourcePerformance()
local resources = GetNumResources()
for i = 0, resources - 1 do
local resourceName = GetResourceByFindIndex(i)
local resourceState = GetResourceState(resourceName)
if resourceState == 'started' then
-- Monitor resource memory usage
local memoryUsage = GetResourceKvpString(resourceName .. '_memory') or '0'
resourceStats[resourceName] = {
memory = tonumber(memoryUsage),
lastCheck = GetGameTimer()
}
end
end
-- Log performance issues
for resourceName, stats in pairs(resourceStats) do
if stats.memory > 100000000 then -- 100MB threshold
print("WARNING: " .. resourceName .. " using " .. stats.memory .. " bytes")
end
end
end
-- Run monitoring every 5 minutes
Citizen.CreateThread(function()
while true do
Citizen.Wait(300000)
MonitorResourcePerformance()
end
end)5. Performance Monitoring
Key Metrics to Monitor
Server Metrics
- • CPU Usage: Keep below 80%
- • RAM Usage: Monitor for leaks
- • Disk I/O: Watch for bottlenecks
- • Network Latency: Track ping times
Game Metrics
- • Server FPS: Maintain 60+ FPS
- • Player Count: Monitor capacity
- • Disconnection Rate: Track stability
- • Response Times: Database queries
Monitoring Tools
-- Simple performance monitoring script
local PerformanceMonitor = {}
function PerformanceMonitor.GetServerStats()
local stats = {
playerCount = GetNumPlayerIndices(),
serverFPS = GetServerTickRate(),
memoryUsage = collectgarbage('count'),
uptime = GetGameTimer()
}
return stats
end
function PerformanceMonitor.LogPerformance()
local stats = PerformanceMonitor.GetServerStats()
-- Log to file or database
local logEntry = string.format(
"[%s] Players: %d, FPS: %.1f, Memory: %dKB",
os.date('%Y-%m-%d %H:%M:%S'),
stats.playerCount,
stats.serverFPS,
stats.memoryUsage
)
print(logEntry)
-- Alert if performance is poor
if stats.serverFPS < 45 then
print("WARNING: Server FPS below 45!")
end
if stats.playerCount > 0 and stats.memoryUsage > 500000 then
print("WARNING: High memory usage detected!")
end
end
-- Monitor every 30 seconds
Citizen.CreateThread(function()
while true do
Citizen.Wait(30000)
PerformanceMonitor.LogPerformance()
end
end)6. Advanced Optimization
Load Balancing
For large communities, consider implementing load balancing across multiple server instances.
Caching Strategies
-- Redis caching implementation
local redis = require('redis')
local cache = redis.connect('127.0.0.1', 6379)
local CacheManager = {}
function CacheManager.GetPlayerData(playerId)
local cacheKey = 'player:' .. playerId
-- Try cache first
local cached = cache:get(cacheKey)
if cached then
return json.decode(cached)
end
-- Fallback to database
local result = MySQL.Sync.fetchAll('SELECT * FROM players WHERE id = @id', {
['@id'] = playerId
})
if result[1] then
-- Cache for 5 minutes
cache:setex(cacheKey, 300, json.encode(result[1]))
return result[1]
end
return nil
end
function CacheManager.InvalidatePlayer(playerId)
local cacheKey = 'player:' .. playerId
cache:del(cacheKey)
endAsync Operations
-- Non-blocking database operations
local function AsyncPlayerSave(playerId, data, callback)
Citizen.CreateThread(function()
-- Simulate heavy database operation
MySQL.Async.execute('UPDATE players SET data = @data WHERE id = @id', {
['@data'] = json.encode(data),
['@id'] = playerId
}, function(affectedRows)
if callback then
callback(affectedRows > 0)
end
end)
end)
end
-- Usage
AsyncPlayerSave(playerId, playerData, function(success)
if success then
print("Player data saved successfully")
else
print("Failed to save player data")
end
end)Conclusion
Optimizing FiveM server performance is an ongoing process that requires monitoring, testing, and continuous improvement. By implementing these techniques, you can provide a smooth, lag-free experience for your players and maintain a thriving server community.
💡 Pro Tip: Start with basic optimizations and gradually implement advanced techniques. Monitor your server's performance regularly and adjust your optimization strategy based on actual usage patterns.
Need Help with Server Optimization?
Our AI script generator can help you create optimized scripts that follow performance best practices. Generate professional FiveM scripts in seconds.
Try AI Generator