Database Integration¶
Most FiveM and RedM RP servers use MySQL for persistent data. The standard library is oxmysql, which provides async MySQL queries from Lua and JavaScript resources.
Setup¶
1. Install oxmysql¶
Download from https://github.com/overextended/oxmysql/releases and place in your server's resources/ folder.
2. Configure the connection string¶
In server.cfg:
set mysql_connection_string "mysql://user:password@localhost/database_name?charset=utf8mb4"
ensure oxmysql
3. Add to fxmanifest.lua¶
The @oxmysql/lib/MySQL.lua import makes the MySQL global available in your server scripts.
Query patterns (Lua)¶
Select (fetch rows)¶
-- Async with callback
MySQL.query('SELECT * FROM players WHERE identifier = ?', {identifier}, function(result)
-- result is an array of rows
end)
-- Async with promise (in a thread)
local result = MySQL.query.await('SELECT * FROM players WHERE identifier = ?', {identifier})
Single row¶
local row = MySQL.single.await('SELECT * FROM players WHERE identifier = ? LIMIT 1', {identifier})
if row then
print(row.name)
end
Single value (scalar)¶
Insert¶
local insertId = MySQL.insert.await('INSERT INTO players (identifier, name) VALUES (?, ?)', {
identifier, playerName
})
Update¶
local affectedRows = MySQL.update.await('UPDATE players SET money = ? WHERE identifier = ?', {
newAmount, identifier
})
Execute (general purpose)¶
Parameterized queries¶
Always use parameterized queries. Never concatenate user input into SQL strings.
-- Good: parameterized
MySQL.query.await('SELECT * FROM players WHERE name = ?', {playerName})
-- DANGEROUS: SQL injection vulnerability
MySQL.query.await('SELECT * FROM players WHERE name = "' .. playerName .. '"')
mysql-async and ghmattimysql (DEPRECATED)¶
Do not use mysql-async or ghmattimysql in new resources. Both libraries are abandoned and unmaintained. oxmysql is the only supported MySQL library for FiveM/RedM as of 2026. If you encounter either in existing code, migrate to oxmysql immediately.
Migration is straightforward: oxmysql is backwards-compatible with mysql-async syntax. In most cases, replacing the dependency in fxmanifest.lua is sufficient:
-- BEFORE (deprecated)
server_scripts {
'@mysql-async/lib/MySQL.lua', -- or @ghmattimysql/...
'server/*.lua'
}
-- AFTER (current standard)
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/*.lua'
}
Legacy API style (still works with oxmysql for backwards compatibility, but prefer the modern API above):
MySQL.Async.fetchAll('SELECT * FROM players WHERE identifier = @id', {['@id'] = identifier}, function(result)
end)
Common schema patterns¶
Players table¶
CREATE TABLE IF NOT EXISTS `players` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`identifier` VARCHAR(60) NOT NULL UNIQUE,
`name` VARCHAR(50) NOT NULL DEFAULT 'Unknown',
`money` INT NOT NULL DEFAULT 0,
`bank` INT NOT NULL DEFAULT 0,
`job` VARCHAR(50) NOT NULL DEFAULT 'unemployed',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Vehicles table¶
CREATE TABLE IF NOT EXISTS `player_vehicles` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`owner` VARCHAR(60) NOT NULL,
`plate` VARCHAR(8) NOT NULL,
`model` VARCHAR(50) NOT NULL,
`stored` TINYINT(1) NOT NULL DEFAULT 1,
`garage` VARCHAR(50) DEFAULT 'default',
INDEX `idx_owner` (`owner`)
);
Inventory table¶
CREATE TABLE IF NOT EXISTS `player_inventory` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`owner` VARCHAR(60) NOT NULL,
`item` VARCHAR(50) NOT NULL,
`count` INT NOT NULL DEFAULT 1,
`metadata` JSON DEFAULT NULL,
INDEX `idx_owner` (`owner`)
);
Migration patterns¶
For schema changes, create numbered SQL migration files:
Run them manually or build a simple migration runner that tracks which migrations have been applied.
Tips¶
- Use indexes on columns you query frequently (identifiers, owner fields)
- Use transactions for operations that must be atomic (transferring money between players)
- Avoid
SELECT *in production -- select only the columns you need - Use
LIMITwhen you only need one row - oxmysql handles connection pooling automatically -- you do not need to manage connections manually
- Test queries with sample data before deploying to a live server