A database server on a VPS usually holds the most valuable data on the machine, and it is often configured once and then forgotten. The defaults in current Debian and Ubuntu packages are reasonable, but a few habits make the difference between a database that is merely installed and one that is safe to leave running: keep it off the network, clean up initial accounts, give applications narrow permissions, and encrypt any traffic that leaves the server.
What your distribution installs
- Debian 12 (bookworm) ships MariaDB 10.11 and Debian 13 (trixie) ships MariaDB 11.8 (package tracker). Neither release carries Oracle's MySQL Server in its main archive.
- Ubuntu 22.04 and 24.04 offer MySQL 8.0, and Ubuntu 26.04 offers MySQL 8.4. MariaDB is also available: 10.6, 10.11 and 11.8 respectively (packages.ubuntu.com).
dpkg -l | grep -E 'mariadb-server|mysql-server'
mariadb --version 2>/dev/null || mysql --versionStep 1: keep it on localhost
If the application runs on the same server, the database should not listen on a public address. The Debian and Ubuntu packages set bind-address = 127.0.0.1: for MariaDB in /etc/mysql/mariadb.conf.d/50-server.cnf, and for MySQL on Ubuntu in /etc/mysql/mysql.conf.d/mysqld.cnf, which also binds the X Protocol port to localhost with mysqlx-bind-address. Confirm what is actually listening:
sudo ss -tlnp | grep -E ':3306|:33060'You want 127.0.0.1:3306, not 0.0.0.0:3306. If another server must connect, bind to a private address rather than a public one, allow port 3306 only from that server in both the host firewall and any cloud firewall, create the user for that host only, and require TLS (step 4).
Step 2: clean up the initial accounts
Both projects ship a script that sets or checks the root password, removes root accounts reachable from other hosts, removes anonymous users and removes the test database that anonymous users can access (mariadb-secure-installation, mysql_secure_installation):
# MariaDB
sudo mariadb-secure-installation
# MySQL
sudo mysql_secure_installationOn Debian and Ubuntu, root@localhost authenticates through the operating system rather than a password: MariaDB uses the unix_socket plugin and Ubuntu's MySQL uses auth_socket. That is why sudo mariadb or sudo mysql opens a root session without a password, and it is safe because it requires root on the server. Keep it that way, and never let an application connect as the database root user. Then review who exists:
SELECT User, Host FROM mysql.user;Remove accounts you do not recognise, and question any account whose host is %, which means any address.
Step 3: one least-privilege user per application
MySQL's security guidelines are blunt: do not grant more privileges than necessary, never grant privileges to all hosts, and never give anyone except root access to the mysql.user table. In practice, give each application its own database and user, limited to that database:
CREATE DATABASE shop;
CREATE USER 'shop_app'@'localhost' IDENTIFIED BY 'long-random-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'shop_app'@'localhost';
-- optional: a separate account for schema migrations
CREATE USER 'shop_migrate'@'localhost' IDENTIFIED BY 'another-long-password';
GRANT ALL PRIVILEGES ON shop.* TO 'shop_migrate'@'localhost';
SHOW GRANTS FOR 'shop_app'@'localhost';Never grant ON *.* to an application account. Store its password in a configuration file readable only by the application's user, not in a world-readable web directory, and use a long random value (for example from openssl rand -base64 32).
Step 4: encrypt connections that leave the server
Connections over the loopback interface or the local socket do not cross the network. For anything else, use TLS:
- MariaDB 11.4 and later, which includes the 11.8 in Debian 13, enable TLS automatically: according to the MariaDB documentation, the server generates certificates at startup and keeps them in memory, and clients verify the server certificate by default for suitable authentication plugins. For production you may still prefer your own certificates.
- Earlier MariaDB, such as 10.11 in Debian 12, needs
ssl_cert,ssl_keyandssl_caset in the server configuration. - MySQL uses the same three settings, and
require_secure_transport=ONmakes encrypted connections mandatory (MySQL encrypted connections).
Per account, REQUIRE SSL forces TLS for that user, which is a good fit for a user that connects from another server:
CREATE USER 'report'@'10.0.0.5' IDENTIFIED BY 'long-random-password' REQUIRE SSL;
GRANT SELECT ON shop.* TO 'report'@'10.0.0.5';
-- from the client, check that the session is encrypted
SHOW STATUS LIKE 'Ssl_version';Step 5: patch and protect the dumps
Install database updates with the rest of the system (sudo apt update && sudo apt upgrade) and restart the service afterwards: sudo systemctl restart mariadb, or mysql for MySQL on Ubuntu. Treat backups as copies of the whole database: dump files from mariadb-dump or mysqldump hold every row in plain text, so store them with restrictive permissions, encrypt them if they leave the server, and test restoring them.
Common pitfalls
- Changing
bind-addressto0.0.0.0and creating users with host%to "make remote access work". - An application connecting as root, or one account shared by several applications.
- A database admin web tool reachable from the whole internet.
- Publishing port 3306 from a Docker container, which bypasses ufw rules.
What you should do
- Run
ss -tlnpand confirm the database listens only on localhost or a private address. - Run the secure-installation script, review
mysql.user, and remove anonymous, remote-root and unknown accounts. - Give each application its own user limited to its own database, and never use root in application configuration.
- Require TLS for every account that connects from another host.
- Keep the server patched, restart it after updates, and protect and test your dumps.
Sources
- mariadb.com/docs/server/clients-and-utilities/deployment-tools/mariadb-secure-installation
- mariadb.com/docs/server/reference/plugins/authentication-plugins/authentication-plugin-...
- mariadb.com/docs/server/security/encryption/data-in-transit-encryption/securing-connect...
- mariadb.com/docs/server/server-management/install-and-upgrade-mariadb/installing-mariad...
- dev.mysql.com/doc/refman/8.4/en/mysql-secure-installation.html
- dev.mysql.com/doc/refman/8.4/en/security-guidelines.html
- dev.mysql.com/doc/refman/8.4/en/using-encrypted-connections.html
- documentation.ubuntu.com/server/how-to/databases/install-mysql
- git.launchpad.net/ubuntu/+source/mariadb/plain/debian/additions/mariadb.conf.d/50-serve...
- git.launchpad.net/ubuntu/+source/mysql-8.0/plain/debian/additions/mysql.conf.d/mysqld.c...
- tracker.debian.org/pkg/mariadb
- packages.ubuntu.com/search?keywords=mysql-server&searchon=names&exact=1&suite=all§i...
- packages.ubuntu.com/search?keywords=mariadb-server&searchon=names&exact=1&suite=all&sec...
Comments
0 total · 0 threads