PiTyUs.Hire me

Engineering

Rate limiting server events in FiveM

Protect FiveM servers from event spam: per-player cooldowns, a reusable token-bucket limiter, limiting expensive callbacks and database work, cleaning up on playerDropped, logging abusers, and the built-in rate limiter convars available on FiveM for GTAV Enhanced.

Updated 9 min readBy PiTyUs · FiveM developer

Overview

Even a perfectly validated event can hurt you if it is called a thousand times a second: database queries pile up, logs explode and the server thread stalls. Rate limiting is the second half of event security — decide how often each player may do each thing, and refuse the rest.

A simple cooldown

server.lualua
local last = {}

local function cooldown(src, key, ms)
    local now = GetGameTimer()
    local k = src .. ':' .. key
    if last[k] and now - last[k] < ms then return false end
    last[k] = now
    return true
end

RegisterNetEvent('fishing:sell', function()
    local src = source
    if not cooldown(src, 'sell', 3000) then return end
    -- validate and pay
end)

A token bucket

shared/limiter.lualua
local buckets = {}

--- allow `burst` calls at once, refilling `rate` per second
function Allow(src, key, rate, burst)
    local now = GetGameTimer() / 1000
    local k = src .. ':' .. key
    local b = buckets[k] or { tokens = burst, at = now }
    b.tokens = math.min(burst, b.tokens + (now - b.at) * rate)
    b.at = now
    buckets[k] = b
    if b.tokens < 1 then return false end
    b.tokens = b.tokens - 1
    return true
end

AddEventHandler('playerDropped', function()
    local prefix = source .. ':'
    for k in pairs(buckets) do
        if k:sub(1, #prefix) == prefix then buckets[k] = nil end
    end
end)

Allow(src, 'chat', 2, 5) lets a player send five messages quickly, then two per second. Good for chat, UI actions and search boxes.

Callbacks and database work

Callbacks that query the database are a favourite spam target. Apply the same limiter at the top of the callback and cache results for a few seconds. ox_lib’s client-side delay argument helps honest clients, but only the server-side check stops abuse — see callbacks.

Built-in limits

FXServer applies its own network limits. On FiveM for GTAV Enhanced they are configurable with rateLimiter_<name>_rate and rateLimiter_<name>_burst convars (for example netEvent, stateBag). These protect the server as a whole; per-action limits in your scripts are still needed.

Logging abuse

Count limit hits per player. A few are normal (double clicks); hundreds in a minute are a script or a cheat. Send those to your staff logs — see Discord webhook logging and anticheat basics.

Frequently asked questions

How do I stop event spam in FiveM?

Add per-player limits in your server event handlers — a cooldown or token bucket — and refuse calls over the limit.

Is a client-side cooldown enough?

No. Cheaters call events directly; the limit must be on the server.

Should I clear limiter data?

Yes, on playerDropped, so the tables do not grow forever.

Does FiveM have built-in rate limits?

Yes for network traffic; on FiveM for GTAV Enhanced they are tunable with rateLimiter_* convars. Script-level limits are still needed.

Need this built, not just explained?

Ten years of FiveM work, from Lua to NUI

Custom resources, React NUI, ESX / QBCore / Qbox integration, OneSync performance audits and security reviews — plus the websites and SEO around your server brand.

Related guides