Hosting
Databases for Hosting (MySQL / MariaDB)¶
Most hosted sites — WordPress, Joomla, Magento, Laravel apps, and countless custom CMSes — keep their content, users, and settings in a relational database. On Linux hosting that database is almost always MariaDB or MySQL. This page covers installing and securing the server, carving out a least-privilege database and user for one website, connecting from an app, the role (and risks) of phpMyAdmin, and day-to-day backup and restore with mysqldump.
Tested on
AlmaLinux 9 / RHEL 9 with mariadb-server from AppStream (MariaDB 10.5). Debian/Ubuntu notes are inline. MariaDB is a drop-in fork of MySQL, so almost everything here applies to both; differences are called out where they matter.
MariaDB vs MySQL¶
Both speak the same SQL dialect and use the same client tools (mysql, mysqldump). MariaDB began as a community fork of MySQL and is the default on RHEL-family distros; Oracle MySQL is also available. For typical website hosting either is fine — pick whichever your application documents support. The commands below use MariaDB but work identically against Oracle MySQL.
Install the server¶
The server listens on TCP port 3306 and also accepts connections over a local Unix socket (/var/run/mysqld/mysqld.sock on Debian, /var/lib/mysql/mysql.sock on RHEL).
Keep the database private
For single-server hosting the database should only ever be reached from localhost. Do not expose port 3306 to the internet. If you must allow remote app servers, restrict it with the firewall and bind only to the internal interface — see How web hosting works.
Secure the installation¶
A fresh install ships with insecure defaults (anonymous users, a test database, remote root login). Fix them with the bundled hardening script:
Answer the prompts:
| Prompt | Recommended answer |
|---|---|
| Switch to unix_socket authentication / set root password | Set a strong root password (or keep socket auth on MariaDB) |
| Remove anonymous users | Yes |
| Disallow root login remotely | Yes |
| Remove test database | Yes |
| Reload privilege tables now | Yes |
Socket auth for root
On modern MariaDB the root database account often authenticates via the Unix socket, meaning you log in simply with sudo mysql as the OS root user — no password needed locally. That is intentional and secure; keep it and create separate password accounts for applications.
Create a database and a least-privilege user¶
Never let a website connect as root. Give each site its own database and its own user, and grant that user rights to only that database. Open a client session:
Then run (replace the names and use a strong, unique password):
-- One database for this website
CREATE DATABASE mysite_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- A dedicated user that may only connect from this server
CREATE USER 'mysite_user'@'localhost' IDENTIFIED BY 'S0me-Strong-Passw0rd!';
-- Grant only what the app needs, scoped to that one database
GRANT ALL PRIVILEGES ON mysite_db.* TO 'mysite_user'@'localhost';
-- Apply the changes
FLUSH PRIVILEGES;
GRANT ALL PRIVILEGES ON mysite_db.* gives full control of that single database (create/alter tables, read, write) but no access to any other database and no server-wide admin rights. The 'mysite_user'@'localhost' host part restricts the account to local connections.
Tighter still
Some applications never alter their schema after install. For those you can drop down to data-only rights and skip CREATE, ALTER, and DROP:
Confirm the grant, then exit:
Connect from an application¶
A PHP app (see PHP and PHP-FPM) needs four things: host, database name, username, password. For WordPress-style config:
DB_HOST = localhost # or 127.0.0.1
DB_NAME = mysite_db
DB_USER = mysite_user
DB_PASSWORD = S0me-Strong-Passw0rd!
There is a subtle but important difference between localhost and 127.0.0.1:
localhost— the client connects over the local Unix socket, which is faster and is the usual default.127.0.0.1— forces a TCP connection to the loopback interface. Use this if the app or driver doesn't know the socket path, or to be explicit.
Test the website's credentials from the shell without involving the app:
If you connect and SHOW TABLES; works, the app will too.
phpMyAdmin¶
phpMyAdmin is a web-based database administration tool written in PHP. It gives you a browser GUI to browse tables, run SQL, import/export data, and manage users — handy for clients who don't use the command line. Most control panels (see Control panels) bundle it.
phpMyAdmin is a frequent attack target
Because it is so common, automated bots constantly scan for exposed phpMyAdmin installs and hammer them with credential-stuffing and exploit attempts. If you run it:
- Do not leave it at a predictable URL like
/phpmyadmin; rename the alias. - Restrict access by IP (web-server
allow/deny) or put it behind HTTP auth / a VPN. - Always serve it over HTTPS — see HTTPS with Let's Encrypt.
- Keep it patched, and remove it entirely if no one is using it.
For routine work the mysql CLI and mysqldump are safer and scriptable.
Backups with mysqldump¶
mysqldump produces a plain-text SQL file (the schema plus INSERT statements) that recreates the database when replayed. It is the workhorse of database backups.
Back up a single database:
Back up all databases on the server in one file:
What the flags do:
--single-transaction— takes a consistent snapshot without locking tables (for InnoDB, the usual storage engine), so the site stays online during the dump.--quick— streams rows instead of buffering the whole table in memory.
Compress on the fly to save space:
mysqldump -u root -p --single-transaction --quick mysite_db | gzip > /backup/mysite_db-$(date +%F).sql.gz
Automate it
A database dump is only useful if it runs every night. Wrap one of these commands in a script and schedule it with cron or a systemd timer — see Cron and timers and the dedicated Backups and migration page. Store the dumps off the server (the 3-2-1 rule), and keep them somewhere only root can read, since they contain all your data.
Restore from a dump¶
Restoring is just feeding the SQL file back into the client. The target database must already exist:
# Create the (empty) database first if it isn't there
sudo mysql -e "CREATE DATABASE IF NOT EXISTS mysite_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# Replay the dump into it
mysql -u root -p mysite_db < /backup/mysite_db.sql
For a gzipped dump, decompress as you pipe it in:
An --all-databases dump already contains the CREATE DATABASE statements, so you restore it without naming a database:
Restoring overwrites
Importing a dump replaces matching tables. Always restore to a scratch database first if you only want to inspect or recover a few rows.
Basic operational issues¶
A few things you will eventually run into when hosting databases:
- Where the data lives. The actual files sit in the data directory:
/var/lib/mysqlon both RHEL and Debian. Each database is a subdirectory. This is on a real disk you must size and monitor — see Storage and filesystems. Don't back up by copying these files while the server is running; usemysqldumpor stop the service first. -
max_connections. The server allows a finite number of simultaneous client connections (default151). A busy or misbehaving site can exhaust them, after which new visitors getERROR 1040: Too many connections. Check the current value and busiest counts:Raise it in the config (
/etc/my.cnf.d/on RHEL,/etc/mysql/mariadb.conf.d/on Debian) under[mysqld], e.g.max_connections = 300, then restart — but first investigate why connections aren't being released, since that's usually the real bug. -
The slow query log. When a site is sluggish, the database is a common culprit. Enable the slow query log to record queries that take too long:
After restarting, queries running longer than
long_query_timeseconds are logged with their execution time, so you can find the offenders and add indexes.
Verify your work¶
# Service is up and enabled
systemctl is-active mariadb && systemctl is-enabled mariadb
# The website database and user exist with the right scope
sudo mysql -e "SHOW DATABASES LIKE 'mysite_db';"
sudo mysql -e "SHOW GRANTS FOR 'mysite_user'@'localhost';"
# The app user can connect and see its tables (will prompt for password)
mysql -u mysite_user -p -e "SHOW TABLES;" mysite_db
# A dump produces a real, non-empty SQL file
mysqldump -u root -p --single-transaction mysite_db | head -n 20
You should see the service active, the database listed, grants limited to mysite_db.*, a successful login as the app user, and readable SQL at the top of the dump.
Summary¶
- MariaDB and MySQL are interchangeable for most hosting; install
mariadb-server, thenenable --nowthe service. - Always run
mysql_secure_installationon a fresh install. - Give every website its own database and its own user, granted rights on that database only (
GRANT ... ON db.*), thenFLUSH PRIVILEGES. - Apps connect with host (
localhost= socket,127.0.0.1= TCP), database, user, and password. - phpMyAdmin is convenient but a heavy attack target — lock it down or skip it.
- Back up with
mysqldump(--single-transaction --quick), automate it on a schedule, store it off-box, and test your restores. - Watch
max_connections, know that data lives in/var/lib/mysql, and use the slow query log to chase performance problems.