Every FiveM server with persistent data — player inventories, vehicles, housing, bank accounts, job history — relies on a database. MySQL (and its drop-in replacement MariaDB) is the standard choice. But "install MySQL and it works" is a massive oversimplification. Poor database configuration is one of the top causes of server lag, data loss, and mysterious bugs.
This guide covers everything from initial installation to advanced optimization. Whether you're setting up your first database or troubleshooting a slow server, you'll find what you need here.
MySQL vs MariaDB: Which One?
Short answer: MariaDB. It's a community-maintained fork of MySQL that's fully compatible but performs better in most benchmarks. Nearly every FiveM hosting provider and VPS template uses MariaDB by default.
| Feature | MySQL | MariaDB |
|---|---|---|
| Performance | Good | Better (especially on reads) |
| Licensing | Oracle (dual-licensed) | GPL (fully open-source) |
| Compatibility | Standard | 100% MySQL compatible |
| Community | Large | Growing, very active |
| FiveM support | Full | Full |
| Recommended | Yes | Preferred |
For the rest of this guide, we'll use "MySQL" to refer to both — the commands and concepts are identical.
Installation
Linux (Ubuntu/Debian)
# Update packages
sudo apt update && sudo apt upgrade -y
# Install MariaDB
sudo apt install mariadb-server mariadb-client -y
# Secure the installation
sudo mysql_secure_installation
# - Set root password: YES (choose a strong password)
# - Remove anonymous users: YES
# - Disallow root login remotely: YES
# - Remove test database: YES
# - Reload privilege tables: YES
# Start and enable on boot
sudo systemctl start mariadb
sudo systemctl enable mariadb
Windows
On Windows, the easiest approach is XAMPP or a standalone MariaDB installer:
- Download MariaDB from mariadb.org
- Run the installer, set a root password, and use default port 3306
- Optionally install HeidiSQL (included in the installer) for a graphical interface
Creating Your FiveM Database
Once MySQL is installed, create a dedicated database and user for your FiveM server. Never use the root account for FiveM — if your server gets compromised, you don't want attackers to have full database access.
# Log into MySQL
sudo mysql -u root -p
# Create the database
CREATE DATABASE fivem_server CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# Create a dedicated user
CREATE USER 'fivem'@'localhost' IDENTIFIED BY 'YourStrongPassword123!';
# Grant permissions only to the FiveM database
GRANT ALL PRIVILEGES ON fivem_server.* TO 'fivem'@'localhost';
# Apply changes
FLUSH PRIVILEGES;
# Exit
EXIT;
Important: Useutf8mb4character set, notutf8. Theutf8encoding in MySQL is actually a broken 3-byte implementation that can't handle emojis and some international characters.utf8mb4is the true UTF-8 implementation.
Connecting FiveM to MySQL
FiveM doesn't connect to MySQL directly — it uses a resource that acts as a bridge. There are two main options:
oxmysql (Recommended)
The modern standard built by the Overextended team. It uses the mysql2 Node.js driver with connection pooling and prepared statements.
Add to your server.cfg:
set mysql_connection_string "mysql://fivem:YourStrongPassword123!@localhost:3306/fivem_server?charset=utf8mb4"
ensure oxmysql
mysql-async (Legacy)
The older option. Still works but doesn't support connection pooling or prepared statements. If you're starting a new server, use oxmysql.
set mysql_connection_string "mysql://fivem:YourStrongPassword123!@localhost:3306/fivem_server?charset=utf8mb4"
ensure mysql-async
Connection String Format
The connection string follows this format:
mysql://USERNAME:PASSWORD@HOST:PORT/DATABASE_NAME?options
# Examples:
# Local server
mysql://fivem:mypass@localhost:3306/fivem_server
# Remote server
mysql://fivem:mypass@192.168.1.100:3306/fivem_server
# With SSL
mysql://fivem:mypass@localhost:3306/fivem_server?ssl=true
Warning: If your password contains special characters (@,#,!, etc.), URL-encode them. For example,p@ss!becomesp%40ss%21. This is the #1 reason "connection refused" errors happen.
Essential MySQL Configuration
The default MySQL configuration is designed for small applications, not game servers handling hundreds of concurrent queries. Here are the most important settings to tune:
my.cnf / my.ini Optimizations
[mysqld]
# Connection pool
max_connections = 200
wait_timeout = 28800
# InnoDB buffer — set to 50-70% of available RAM
# For a 4GB VPS: 2G. For 8GB: 4G. For 16GB: 8G.
innodb_buffer_pool_size = 2G
# Write performance
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
# Query cache (MariaDB)
query_cache_type = 1
query_cache_size = 128M
query_cache_limit = 2M
# Temp tables
tmp_table_size = 64M
max_heap_table_size = 64M
# Slow query log — find problematic queries
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
After editing, restart MySQL:
sudo systemctl restart mariadb
Database Optimization for FiveM
Indexing
Indexes are the single most impactful optimization you can make. An index is like a book's table of contents — instead of scanning every row, MySQL can jump directly to the data it needs.
-- Check which queries are slow
SHOW FULL PROCESSLIST;
-- Add indexes to commonly searched columns
-- Players table
ALTER TABLE players ADD INDEX idx_citizenid (citizenid);
ALTER TABLE players ADD INDEX idx_license (license);
-- Vehicles table
ALTER TABLE player_vehicles ADD INDEX idx_citizenid (citizenid);
ALTER TABLE player_vehicles ADD INDEX idx_plate (plate);
-- Inventory/stashes
ALTER TABLE stashitems ADD INDEX idx_stash (stash);
-- Phone messages
ALTER TABLE phone_messages ADD INDEX idx_sender_receiver (sender, receiver);
Pro tip: Enable the slow query log (shown in the config above) and check it after a busy play session. Any query taking more than 1 second will be logged, showing you exactly what needs indexing or optimization.
Table Maintenance
Over time, tables accumulate fragmentation from constant inserts, updates, and deletes. Run these periodically (weekly is good):
-- Optimize all tables in your FiveM database
-- This reclaims fragmented space and updates statistics
USE fivem_server;
-- For each important table:
OPTIMIZE TABLE players;
OPTIMIZE TABLE player_vehicles;
OPTIMIZE TABLE stashitems;
OPTIMIZE TABLE phone_messages;
OPTIMIZE TABLE bank_accounts;
Cleaning Old Data
Some tables grow endlessly if not maintained:
-- Delete old phone messages (older than 30 days)
DELETE FROM phone_messages WHERE timestamp < DATE_SUB(NOW(), INTERVAL 30 DAY);
-- Delete old log entries
DELETE FROM server_logs WHERE timestamp < DATE_SUB(NOW(), INTERVAL 7 DAY);
-- Delete orphaned vehicle entries (vehicles with no owner)
DELETE FROM player_vehicles WHERE citizenid NOT IN (SELECT citizenid FROM players);
-- Clean empty stashes
DELETE FROM stashitems WHERE items = '[]' OR items IS NULL;
Backups — Non-Negotiable
If you take nothing else from this guide, take this: back up your database. Data loss happens — corrupted tables, accidental deletions, ransomware, failed updates. A backup is the difference between "minor inconvenience" and "server is dead."
Manual Backup
# Full database dump
mysqldump -u fivem -p fivem_server > backup_$(date +%Y%m%d_%H%M%S).sql
# Compressed backup
mysqldump -u fivem -p fivem_server | gzip > backup_$(date +%Y%m%d).sql.gz
Automated Backups (Cron Job)
# Edit crontab
crontab -e
# Add this line for daily backups at 4 AM
0 4 * * * mysqldump -u fivem -pYourPassword fivem_server | gzip > /home/backups/fivem_$(date +\%Y\%m\%d).sql.gz
# Keep only last 14 days of backups
0 5 * * * find /home/backups/ -name "fivem_*.sql.gz" -mtime +14 -delete
Pro tip: Store backups on a different disk or server than your database. If the server's disk fails, your backups are gone too if they're on the same disk. Cloud storage (S3, Google Drive, Backblaze B2) is cheap insurance.
Common Database Issues
1. "Too many connections"
This means your FiveM resources are opening database connections faster than they're closing them. Fix:
-- Check current connections
SHOW PROCESSLIST;
-- Increase max_connections in my.cnf
max_connections = 300
-- But also fix the root cause: scripts not closing connections
-- Make sure you're using oxmysql with connection pooling
2. "Table is full"
Usually means you've run out of disk space, or the table has hit the InnoDB file size limit:
# Check disk space
df -h
# Check table sizes
SELECT table_name,
ROUND(data_length/1024/1024, 2) as 'Data (MB)',
ROUND(index_length/1024/1024, 2) as 'Index (MB)'
FROM information_schema.tables
WHERE table_schema = 'fivem_server'
ORDER BY data_length DESC;
3. Slow queries causing server lag
When a database query takes too long, it blocks the FiveM server thread. Check the slow query log and use EXPLAIN to analyze:
-- See what's running right now
SHOW FULL PROCESSLIST;
-- Analyze a specific query
EXPLAIN SELECT * FROM players WHERE license = 'license:abc123';
-- If the "type" column says "ALL" — you're missing an index
4. Data corruption after crash
# Check tables for errors
mysqlcheck -u root -p --check fivem_server
# Repair corrupted tables
mysqlcheck -u root -p --repair fivem_server
Security Best Practices
- Never expose MySQL to the internet: Bind to
127.0.0.1unless you specifically need remote access - Use strong passwords: At least 16 characters, mixed case, numbers, symbols
- Separate users per application: FiveM, website, and other apps should each have their own database user
- Principle of least privilege: The FiveM user only needs access to the FiveM database — never grant global privileges
- Regular updates: Keep MariaDB/MySQL updated to patch security vulnerabilities
- Monitor for unusual queries: Enable the general log temporarily if you suspect someone is running unauthorized queries
A well-configured database is the foundation of a stable FiveM server. Invest the time to set it up correctly, create a backup routine, and monitor performance regularly. Your server — and your players' data — will thank you. For scripts that are built with database performance in mind, check out our store.