Skip to content
Blog

Undo a FiveM dupe or money exploit with a database backup

Someone duped items or spawned money? Find when it started, pick the backup from just before it and roll the database back without losing more than you must.

By PK

8 min read
  • Backups
  • Rollback
  • Dupes
  • Economy
On this page

When a player dupes items or a cheater spawns money on your FiveM server, the cleanest fix is to restore the database from a backup taken just before it started. Deleting the copies by hand rarely works, because by the time you notice, the money and the items have already moved to other players. This post covers how these exploits usually happen, how to find the right restore point, when to roll back everyone and when only a few players, and how FiveDock’s backups do it from the panel.

Most servers find FiveDock through its CDN, for ox_inventory images and phone photos. FiveDock also backs up your server’s database, on every plan including Free, and that is the part that saves you on the night someone breaks the economy.

What a dupe or money exploit looks like

It usually starts with a message in Discord. Someone is selling rifles at half price, a new player bought three supercars on day one, or the market is suddenly full of an item that should be rare. You check, and one character has 40 million in the bank while the next richest has 200 thousand.

Behind it there is almost always one of these:

  • A server event that trusts the client. A job script pays whatever amount the client sends, and someone with a cheat menu calls that event with 9,999,999 instead of 450.
  • A race in the inventory. Two players move the same stack at the same moment, a trade finishes just as one of them disconnects, or the server crashes after an item moved but before the next save. The item ends up in both places.
  • A shop or crafting script that pays before it checks. It hands out the money and only then tries to remove the item, or it accepts a negative amount.
  • A staff mistake. A /givemoney with three zeros too many, or a staff account someone else got into.

Why cleaning it up by hand rarely works

The first instinct is to wipe the cheater’s money and ban them. That fixes one row. By the time you find out, the money has usually gone into cars, houses and other players’ pockets, and the duped items have been sold, stored in stashes and handed to friends. Every one of those is another row in another table, and you will miss some.

A backup from before the exploit has none of that. Put it back and the copies are gone everywhere at once, including the places you would never think to look.

Find the right restore point

The restore point is the newest backup taken before the exploit started. One taken later already contains the copies. To find it:

  1. Find the first exploited event. Your money logs, the player’s history in txAdmin or the time an alert fired tell you roughly when the first strange transfer or item appeared.
  2. Pick the last backup before that moment, not the last backup before you noticed.
  3. Check that it is clean before you use it. Load it into a separate database next to the live one and compare the balances.
terminal
mysql -u root -p -e "CREATE DATABASE restore_check"
mysql -u root -p restore_check < fivem-2026-10-23-2000.sql

Then list who gained the most since that backup. On QBCore and Qbox:

QBCore · Qbox
SELECT live.citizenid,
  CAST(JSON_EXTRACT(old.money, '$.bank') AS SIGNED) AS bank_then,
  CAST(JSON_EXTRACT(live.money, '$.bank') AS SIGNED) AS bank_now,
  CAST(JSON_EXTRACT(live.money, '$.bank') AS SIGNED)
    - CAST(JSON_EXTRACT(old.money, '$.bank') AS SIGNED) AS gained
FROM fivem.players AS live
JOIN restore_check.players AS old ON old.citizenid = live.citizenid
ORDER BY gained DESC
LIMIT 20;

On ESX the money sits in the accounts column of users:

ESX
SELECT live.identifier,
  CAST(JSON_EXTRACT(old.accounts, '$.bank') AS SIGNED) AS bank_then,
  CAST(JSON_EXTRACT(live.accounts, '$.bank') AS SIGNED) AS bank_now,
  CAST(JSON_EXTRACT(live.accounts, '$.bank') AS SIGNED)
    - CAST(JSON_EXTRACT(old.accounts, '$.bank') AS SIGNED) AS gained
FROM fivem.users AS live
JOIN restore_check.users AS old ON old.identifier = live.identifier
ORDER BY gained DESC
LIMIT 20;

Swap $.bank for $.cash ($.money on ESX) to check cash. Characters created after the backup don’t show up in this list, so look at those separately. If the cheater’s balance in the backup looks normal, it is a good restore point. If it is already huge there, go one backup further back.

The same query shows where the cheater sent the money. A player who made a few million in an hour without a job that pays that well is usually where it went.

Why backup frequency decides how much you lose

A rollback takes every player back to the moment of the backup, so everything they did since is lost too. With one backup a night at 04:00 and an exploit found at 21:00, the whole city loses 17 hours of play. With a backup every hour it loses less than one.

That is why the time between the exploit and the moment you notice it matters as much as the backup itself. Alerts that tell you within minutes keep the rollback short.

Roll back everyone, or only a few players

Roll back the whole database when the copies spread: many players are involved, the bug hit the whole economy, or you can’t tell who holds what. Everyone loses the same few hours, but the economy is clean again.

Restore only a few players when one or two people did it and the copies didn’t travel far. You put their rows back from the backup and nobody else loses anything. Restoring one player’s inventory shows how, with SQL for ESX and QBCore.

Restoring only the cheater while their copies sit in other players’ inventories leaves the dupe in the game. Check where the items and the money went before you pick this route.

How FiveDock’s backups handle it

FiveDock does all of this from the panel, through the agent that already runs on your server for the CDN and everything else. Each backup is encrypted on your machine with a key we never see.

  • Backups on every plan. Free backs up once a day and keeps 7 days, City once a day for 30 days. Metro backs up every hour and keeps the last 24 hours hour by hour, then one a day for 30 days and one a week for 12 weeks.
  • A backup the moment an alert fires. Money alerts, on every plan, post to Discord when a single transfer crosses a threshold or a player gains money too fast. Duplicate item alerts on Metro catch the same unique item in two places, or a stack that grows with nothing to explain it. Each alert takes a backup that same second and links it to the finding, so you keep a frozen record of who held what when it was caught.
  • A preview before anything changes. Pick a backup and see what the rewind will change before you confirm. The whole database or the whole server works on every plan; one table or one player is Metro.
  • A safety backup first. Before every rewind, FiveDock backs up the current state. Picked the wrong hour? Go back to where you were.
  • The framework can’t undo your work. A database rewind is refused while ESX, QBCore or Qbox is running, because the framework would write the players it holds in memory back over the restore. A player restore is refused while that player is connected. You can force either one if you know what you are doing.
  • Only owners can rewind, and every rewind goes in the audit log. A deleted backup stays locked for 30 days, so even a stolen staff account can’t wipe your history.

Prices and the full list of what each plan includes are on the pricing page. To see how these backups are made and tested by hand, read backing up a FiveM server.

Before you start the server again

Fix the hole first. If the exploit came from a script, stop that resource or patch it before the restart, or it will happen again within the hour. For a money event, the server decides the amount, never the client:

server.lua
-- Exploitable: the client decides how much it gets paid
RegisterNetEvent('delivery:pay', function(amount)
  local xPlayer = ESX.GetPlayerFromId(source)
  xPlayer.addMoney(amount)
end)

-- Safe: the server decides the amount and checks the job was done
local PAY = 450
local onDelivery = {} -- set by the server when it hands out a job

RegisterNetEvent('delivery:finish', function()
  local src = source
  if not onDelivery[src] then return end
  onDelivery[src] = nil
  ESX.GetPlayerFromId(src).addMoney(PAY)
end)
  1. Ban the cheater by their license and the other identifiers txAdmin shows, not just their character.
  2. Tell your players what time you rolled back to and why. People take a lost evening much better when they know it was a cheater and not you.
  3. Keep the safety backup and the alert backup for a while. They show what happened if someone appeals the ban.

Common questions

How far back should I roll back a FiveM server after a dupe?

To the newest backup taken before the first exploited event, not before you noticed. Load it into a separate database first and check that the cheater’s balance and items look normal there.

Will players lose progress if I roll back the database?

Yes, everything since the backup. With hourly backups that is under an hour, with nightly backups it can be most of a day. If only a few players were involved, restore just their rows instead.

A cheater gave themselves money. Can I just remove it?

Only if the money never left their character. Usually it has already gone into cars, houses or other players’ accounts, and removing it from one row leaves the rest. Rolling back to a backup from before is faster and catches everything.

Can txAdmin roll back the database?

No. txAdmin manages the server process, bans and player history, but it doesn’t back up or restore your MySQL or MariaDB database. You need mysqldump on a schedule or a tool like FiveDock.

Are FiveDock backups included on the free plan?

Yes. Free takes a daily backup, keeps it for 7 days and can restore the whole database. Hourly backups, duplicate item alerts and restoring one player are on Metro.

All articles