Most frameworks will not start without a database, and the errors when it is wrong tell you almost nothing. Six checkpoints, each of which can be passed or failed on its own — so that a failure means something.
The reason this eats an evening is not difficulty. Every individual step here is small. The problem is that if you do all of them and then start the server, a failure could be any of six things, and the message you get will not distinguish between them — a framework that cannot reach the database and a framework reaching the wrong database report almost identically.
So do them one at a time and confirm each before moving on. What follows assumes a machine with no database on it at all, which is the situation more often than people expect.
01
Is one already installed?
# Windows — is a service already registered?
sc query MariaDB
sc query MySQL
# Or, more thoroughly:
Get-Service | Where-Object { $_.Name -match 'maria|mysql' }
Pass looks like
A service is listed and RUNNING. You already have a database — skip to checkpoint 3 and do not install a second one.
If it does not
Nothing listed. Nothing is wrong; you simply have a clean machine and need to install one.
02
Install it, and confirm the service exists
# after installing MariaDB or MySQL:
sc query MariaDB
# expected, roughly:
# STATE : 4 RUNNING
Pass looks like
STATE reads RUNNING. A database that is installed but not running as a service will work today and fail silently after the next reboot.
If it does not
Installed but STOPPED or absent means the installer did not register a service. Start it and set it to start automatically before going further.
03
Can YOU connect to it?
mysql -u root -p -e "SELECT VERSION();"
Pass looks like
A version number prints. This proves the server is running, listening, and that you hold credentials that work.
If it does not
Access denied means the password is not what you think. Can't connect means it is not listening. These are completely different problems and this is the only step that separates them cleanly.
04
Make a user and a schema for this server only
CREATE DATABASE fivem CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'fivem'@'localhost' IDENTIFIED BY 'a-password-you-chose';
GRANT ALL PRIVILEGES ON fivem.* TO 'fivem'@'localhost';
FLUSH PRIVILEGES;
Pass looks like
No errors. You now have a user that can touch this schema and nothing else.
If it does not
If you are tempted to skip this and use root: the framework will work, and so will anything else that ever reaches your database. Scope it now while it costs one command.
05
Connect as that user, not as root
mysql -u fivem -p fivem -e "SELECT DATABASE();"
Pass looks like
It prints fivem. The credentials your server is about to use are now proven, by you, before any framework is involved.
If it does not
Access denied here while root worked means the grant or the host part ('localhost' vs '%') is wrong — not the password.
06
Give the server the same details, exactly
set mysql_connection_string "mysql://fivem:a-password-you-chose@localhost/fivem?charset=utf8mb4"
Pass looks like
The framework starts and reports a connection. Every value in that string is one you personally proved at checkpoint 5.
If it does not
If it fails now, it is the string itself — not the database. Read the password trap below before you change anything else.
The password trap
That connection string is a URI, which means a handful of characters inside it are not data — they are punctuation. A password containing @, :, / or # will be parsed as a boundary, and the resulting error will talk about a host or a database that you have never heard of, because the parser split the string somewhere you did not intend.
Either choose a password without those characters, or percent-encode them. This single issue accounts for an unreasonable share of “the database works but the server cannot connect”.
A related one, and this is a defect we shipped ourselves: an installer that generates a database password for you, stores it, and never shows it to you is fine right up until the moment something needs to be changed by hand — or until an update replaces the folder it was written into. The user then has a working server, no idea what the credentials are, and no way to recover them. We moved ours out of the install directory and wrote a migration for the people who already had one. If you use a tool that invents a password, find out where it put it, today, while everything still works.
Two more that cost hours
localhost is not always 127.0.0.1
Depending on the client and platform, localhost may resolve to a socket connection rather than a TCP one — different path, different permissions, different result. If a connection works in your terminal and fails from the server with identical credentials, try 127.0.0.1 before you assume the credentials are wrong.
Use utf8mb4, not utf8
The encoding historically called utf8 in MySQL does not cover the whole of Unicode. Names and chat containing emoji or non-Latin characters will insert as mangled text or fail outright, and it will look like a bug in whatever resource happened to be writing at the time. Create the schema as utf8mb4 and say so in the connection string. Fixing this after there is data in the table is a migration; doing it now is one word.
Why the order matters
Every checkpoint above fails in a way that points at itself. That is the entire value of doing it this way: by the time you start the framework, the only new variable is the framework. If it cannot connect at step six, you are not wondering whether the database is installed, whether it is running, whether the password is right or whether the user exists — you proved all four, in order, with your own hands.
Skipping to the end is not faster. It just moves all six questions to the same moment and gives you one error message to answer them with.