Database setup: MariaDB, HeidiSQL and oxmysql
Install MariaDB on Windows or Linux, manage it with HeidiSQL, connect FiveM with oxmysql and mysql_connection_string, import SQL files and back up your data.
Diese Doku ist vorerst auf Englisch.
Frameworks like QBCore, Qbox and ESX store characters, money, vehicles and inventories in a SQL database. FiveM talks to it through a resource, almost always oxmysql. A plain vMenu server does not need any of this.
Use MariaDB, not XAMPP
- MariaDB is what the frameworks target. The oxmysql docs say MariaDB is “highly recommended for compatibility and improved performance” over MySQL 8 (which has reserved keyword and default value differences that break some scripts).
- Qbox requires at least MariaDB 10.9 and recommends a current LTS release. The ESX docs say to use MariaDB only.
- XAMPP bundles an old MariaDB with a web server you don’t need. Both the ESX and Qbox docs tell you not to use it. If you’re on XAMPP now, dump your database and move it to a real MariaDB install.
Install on Windows
- Download the MSI from mariadb.org/download (pick the current LTS).
- Run it. Set a root password and keep “Install as service” checked. Leave “Enable access from remote machines for root” unchecked.
- The Windows installer includes HeidiSQL, a free GUI for the database. Keep it selected.
- Default port is
3306. Keep it unless something else uses it.
Install on Linux
sudo apt install -y mariadb-server
sudo mariadb-secure-installationThen create a dedicated user in the MariaDB shell (sudo mariadb):
CREATE USER 'fivem'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON *.* TO 'fivem'@'localhost';
FLUSH PRIVILEGES;The broad grant lets the txAdmin deployer create a database. After deploying, you can restrict it to one database: GRANT ALL PRIVILEGES ON qbox_4f2a.* TO 'fivem'@'localhost'; and revoke the rest. Manage it from your PC with HeidiSQL over an SSH tunnel (HeidiSQL supports “MariaDB or MySQL (SSH tunnel)”) instead of opening port 3306.
HeidiSQL basics
- Open HeidiSQL, click New, network type MariaDB or MySQL (TCP/IP), host
127.0.0.1, userroot(orfivem), your password, port3306. Save and Open. - Create a database: right click the connection > Create new > Database. Collation
utf8mb4_unicode_ciorutf8mb4_general_ci. - Import a
.sqlfile (a resource’s install SQL): select the database, then File > Run SQL file… and pick the file. - Browse data: click a table, then the Data tab. Handy for checking a player’s money or job while testing.
- Back up: right click the database > Export database as SQL, tick “Create” for tables and “Insert” for data.
Let txAdmin create it
When you deploy a framework recipe in txAdmin, the deployer asks for host, port, user and password and creates the database for you if you leave the name empty (it generates a random name like QBCore_A1B2C3). It also imports the framework’s SQL and writes the connection string into server.cfg through the {{dbConnectionString}} placeholder. That’s the easiest path.
Connect with oxmysql
oxmysql reads one convar. Put it in server.cfg (or better, in a secrets.cfg you exec) before ensure oxmysql:
set mysql_connection_string "mysql://fivem:password@localhost:3306/qbox_4f2a?charset=utf8mb4"
ensure oxmysqlBoth formats from the oxmysql docs work:
# URI
set mysql_connection_string "mysql://root:12345@localhost:3306/fivem"
# key=value
set mysql_connection_string "user=root;password=12345;host=localhost;port=3306;database=fivem"Warning
Don’t use these characters in the database password: ; , / ? : @ & = + $ #. They break the connection string parsing. Use a long password made of letters and numbers instead.
Useful oxmysql convars:
set mysql_slow_query_warning 150 # warn about queries slower than 150 ms
set mysql_debug false # true, or a list like ["ox_inventory"] to log queriesUsing the database in your own resource
Add oxmysql’s library to your manifest:
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/main.lua',
}
dependency 'oxmysql'Then query from server scripts. Always use placeholders (?) for values, never string concatenation:
-- one row
local row = MySQL.single.await('SELECT money FROM my_accounts WHERE identifier = ?', { identifier })
-- one value
local count = MySQL.scalar.await('SELECT COUNT(*) FROM my_accounts')
-- many rows
local rows = MySQL.query.await('SELECT * FROM my_accounts WHERE money > ?', { 1000 })
-- insert, returns the new id
local id = MySQL.insert.await('INSERT INTO my_accounts (identifier, money) VALUES (?, ?)', { identifier, 500 })
-- update, returns affected rows
local changed = MySQL.update.await('UPDATE my_accounts SET money = money + ? WHERE identifier = ?', { 250, identifier })Caution
Never build SQL from strings a client sent you: '... WHERE name = "' .. name .. '"' is an SQL injection waiting to happen. Placeholders escape values for you.
Database code only runs on the server. Clients must never talk to the database directly. They ask the server with an event or callback, and the server checks and queries. See Client, server and events.
Backups
Set these up before you have players, not after the first disaster.
Windows: a scheduled task that runs mariadb-dump (or mysqldump, both ship with MariaDB) every night:
@echo off
set STAMP=%DATE:~-4%-%DATE:~3,2%-%DATE:~0,2%
"C:\Program Files\MariaDB 11.4\bin\mariadb-dump.exe" -u root -pYOURPASSWORD --single-transaction qbox_4f2a > C:\Backups\db-%STAMP%.sqlAdjust the MariaDB folder and date format to your system.
Linux: a cron job for the fivem user:
crontab -e
# every night at 04:30, keep 14 days
30 4 * * * mariadb-dump --single-transaction qbox_4f2a | gzip > /home/fivem/backups/db-$(date +\%F).sql.gz && find /home/fivem/backups -name 'db-*.sql.gz' -mtime +14 -deletePut credentials in ~/.my.cnf (mode 600) so they don’t appear in the crontab:
[client]
user=fivem
password=a-long-random-passwordCopy backups off the machine too (another server, object storage). A backup on the same disk doesn’t help when the disk dies.
Common database errors
| Error / symptom | Fix |
|---|---|
ECONNREFUSED 127.0.0.1:3306 |
MariaDB isn’t running, or it’s on another port. Start the service. |
ER_ACCESS_DENIED_ERROR |
Wrong user or password in mysql_connection_string, or the user has no rights on that database. |
ER_BAD_DB_ERROR: Unknown database |
The database name in the string doesn’t exist. Create it or fix the name. |
ER_NO_SUCH_TABLE |
You didn’t import the resource’s .sql file. |
Emojis or special names turn into ???? |
Use utf8mb4 for the database and add ?charset=utf8mb4 to the URI. |
| Framework loads, but nothing saves | oxmysql started after the framework. Put ensure oxmysql first. |
Next: Common errors and fixes.
