Initialise a MariaDB Data Directory Safely with mysql_install_db

Every MariaDB server starts life as an empty data directory until mysql_install_db lays down its system tables. You will finish with MariaDB system tables in a new data directory, owned by the account that will run the server, and a short verification path. On this Ubuntu installation, mysql_install_db is a symlink to mariadb-install-db from MariaDB 10.11.14-0ubuntu0.24.04.1.

Allow 15 to 30 minutes. You need the MariaDB server package, a shell, a completely new or intentionally disposable data directory, and sudo access if the server will run as the mysql user. The command creates system tables and account records. It is an initialisation tool, not a harmless status check.

1. Check the installed command

First confirm the compatibility name and read the local options. These are ordinary read-only commands:

$ command -v mysql_install_db
/usr/bin/mysql_install_db
$ ls -l /usr/bin/mysql_install_db /usr/bin/mariadb-install-db
lrwxrwxrwx ... /usr/bin/mysql_install_db -> mariadb-install-db
$ dpkg-query -W -f='${Package} ${Version}\n' mariadb-server-core
mariadb-server-core 1:10.11.14-0ubuntu0.24.04.1
$ mysql_install_db --help

The exact link metadata and help text can differ, but the important local fact is that both names invoke the same MariaDB script. The MariaDB name is the current one; the MySQL-shaped name remains for compatibility.

Checkpoint: Stop here if the command is missing, or if the installed package is not the server implementation you intend to initialise.

2. Choose a new data directory

Set a path that is empty and reserved for this MariaDB instance. Do not point the example at a live server's directory. Check it before running anything that changes state:

$ DATADIR=/srv/mariadb/data
$ if [ -e "$DATADIR/mysql" ]; then
>     printf 'Refusing to initialise an existing data directory: %s\n' "$DATADIR" >&2
>     exit 1
> fi
$ printf 'Selected data directory: %s\n' "$DATADIR"
Selected data directory: /srv/mariadb/data

A directory containing mysql is a strong warning that system tables already exist. Do not add --force to push past that warning without a backup and a documented recovery plan. Re-running initialisation against a service data directory can damage the instance or produce accounts and tables you did not expect.

3. Decide which operating-system account will run MariaDB

The files must be accessible to the account that later runs mariadbd. If this is a packaged service, that account is commonly mysql. If you are creating a private test instance as your own user, initialise it as that user and use a directory you can write.

When running as root, --user tells the script which login user will run mariadbd; the local help says this option requires root. --group can select its group where the installed script supports it. Do not guess a service account: check the unit or package configuration first.

4. Initialise the system tables

This is the state-changing step. The following example is for a new packaged-style instance. It deliberately puts --no-defaults first, so an unrelated option file cannot silently redirect the operation or add server arguments:

$ sudo mariadb-install-db --no-defaults \
    --user=mysql \
    --basedir=/usr \
    --datadir="$DATADIR"
Installing MariaDB/MySQL system tables in '/srv/mariadb/data' ...
OK
...
Two all-privilege accounts were created.

The paths are examples. Use the actual MariaDB installation directory and data directory for your host. The script invokes mariadbd in bootstrap mode to create the system tables. It may print a longer account and service message; a final non-zero status is failure even if earlier lines contain OK.

Warning: Do not paste the command into a production host until you have confirmed that DATADIR is the intended new directory. There is no general undo command for an initialised directory. Recovery means stopping any process using it, restoring or removing that disposable directory according to your backup policy, and starting again with the correct path.

5. Check ownership and the created tables

Use read-only filesystem checks after the command returns:

$ stat -c '%U:%G %n' "$DATADIR" "$DATADIR/mysql"
mysql:mysql /srv/mariadb/data
mysql:mysql /srv/mariadb/data/mysql
$ test -f "$DATADIR/mysql/user.frm" || test -f "$DATADIR/mysql/global_priv.frm"
$ printf 'system-table directory exists\n'
system-table directory exists

MariaDB versions use different table-file layouts, so the two alternatives make the check useful on this 10.11 installation and older layouts. Also check the exit status directly when scripting:

$ printf 'initialisation status: %s\n' "$?"
initialisation status: 0

Run that immediately after the installer, before another command replaces $?. If ownership is wrong, do not start the server. Fix the directory ownership deliberately with chown after confirming the service account and the exact directory.

6. Understand the initial accounts

Current MariaDB help and documentation describe --auth-root-authentication-method=socket as the default. This creates local socket-based root access for the operating-system root account and avoids putting a usable initial password in the new instance. The installer also creates a second privileged account based on --user unless you choose another name with --auth-root-socket-user.

The alternative --auth-root-authentication-method=normal creates a root account with no initial password. That is a security-sensitive choice: use it only when you have an immediate, controlled password-setting procedure and local exposure is understood. Do not put a database password directly in shell history or a process list.

The installer output on this host says that the created accounts have no password and explains that system-root access is required for the root account. Treat that as an authentication reminder, not as permission to leave a new service unattended.

7. Avoid unwanted defaults

The script can read option groups such as [mysql_install_db] and server groups from option files. That is useful for a managed installation, but it is a common source of surprising paths and permissions. Use --no-defaults first, as above, for an isolated test. If you need a controlled configuration file, use --defaults-file=FILE as the first argument and inspect the file before running.

For a small test instance, --skip-test-db omits the test database. The local help also exposes --skip-name-resolve, which uses IP addresses rather than host names in grant entries. Choose that only because your name-resolution design requires it; it is not a repair for a generally broken installation.

8. Start and verify only after initialisation

Initialising tables does not make a daemon run at boot. The installer prints a suggested mariadbd-safe command, but service management belongs to your distribution or deployment. Before starting anything, confirm that no existing MariaDB service already owns the selected port or data directory.

After starting the instance through its intended service definition, connect using the authentication method you selected and check the server version and system database:

$ sudo mariadb -e 'SELECT VERSION(); SHOW DATABASES;'
VERSION()
10.11.x-MariaDB-...
Database
information_schema
mysql
performance_schema

Do not treat a successful client connection as proof that the service is correctly configured. Also verify the service status, error log and exact data directory. If initialisation fails, inspect the error log in that data directory and correct one cause at a time. Do not repeatedly add flags until the error disappears.

Done means