Running your own database on a VPS gives you version choice and configuration control. It also makes you responsible for three things nobody handles for you: that it is not reachable from the internet, that it is configured for the memory the machine actually has, and that it is backed up in a way that restores.
Bind it to localhost
The single most important setting. A database listening on a public address is scanned and attacked within hours of the server becoming reachable.
Unless something genuinely connects from another machine, bind to 127.0.0.1 and confirm it with a port check from outside. The application on the same server connects locally and is unaffected.
If remote access is genuinely required, allow it from specific addresses through the firewall rather than opening the port to everyone, or better, tunnel it over SSH so nothing is exposed at all.
One user per application
Create a database, then a user with privileges on that database only. Never connect an application as the administrative user.
The difference matters when an application is compromised: a scoped user exposes one database, an administrative user exposes every database on the server.
Default configuration is sized for nothing
A stock database configuration is deliberately conservative so it starts anywhere. On a server with real memory it uses a fraction of what is available, and the symptom is a database that is slow for no visible reason.
The buffer pool (the memory the database uses to hold data and indexes) is the setting that matters most. Raising it to a sensible share of the machine's memory is frequently the largest single performance change available.
Leave room for everything else. A database configured to use most of the memory on a machine also running a web server produces the other failure: the kernel starts killing processes, and what it kills is usually the database.
Slow queries are usually the real problem
Before adding resources, find out what the database is actually doing. Enable slow query logging and read it after a day.
What you nearly always find is one query, running constantly, missing an index. Adding that index frequently does more than doubling the server's memory, and it costs nothing.
Scaling hardware to accommodate a missing index is a permanent tax on an afternoon's work.
Dump, do not copy
Backing up a database by copying its files while it is running produces an inconsistent copy that may not restore, and you find that out during a restore.
Use the database's own dump tool, which produces a consistent snapshot. Then compress it, push it off the server, and delete local copies on a schedule.
Test a restore once, deliberately, into a scratch database. An untested dump is a hypothesis, and a truncated dump looks exactly like a complete one until you try to use it. Backing up your VPS goes into the discipline.
Character set
Set it explicitly when creating databases rather than accepting a default. Getting this wrong surfaces later as mangled characters in stored text, and correcting it after data exists is considerably more work than choosing correctly at the start.
Keep it patched
Database software receives security updates like anything else. Automatic security updates cover it, and a database is a poor thing to leave unpatched given what it holds.
Note that a version upgrade is a different operation from a security patch. Take a snapshot and a dump before one. Understanding KVM virtualization goes into what a snapshot does and does not protect.
If the database is genuinely your constraint, How to Tune MySQL or MariaDB on a Small VPS goes into the two settings that matter and where tuning stops helping.
If the same server is also handling mail, Setting Up VPS for E mail Services deals with what that commits you to.
Find the queries that cost the most
Database tuning without measurement is guesswork, and the record of what is slow is one setting away.
mysql -e "SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1;" mysqldumpslow -s t /var/log/mysql/slow.log 2>/dev/null | head -20 mysql -e "SHOW FULL PROCESSLIST" | awk '$6 > 5'
Leave it on for a day of normal traffic. The summary groups similar queries and ranks them by total time, which is more useful than the single slowest one, because a fast query running ten thousand times costs more than a slow one running twice.
Turn it off afterwards. The log grows steadily and a threshold set too low on a busy server produces a file that fills the disk.
Size the memory pool to the data
One setting accounts for most of the difference between a database that feels fast and one that does not.
mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size'"
mysql -e "SELECT table_schema, ROUND(SUM(data_length+index_length)/1048576) AS mb
FROM information_schema.tables GROUP BY table_schema ORDER BY mb DESC;"
free -m
Compare the pool size against the total data size. When the pool is smaller, the database reads from disk repeatedly for data it could have held in memory, and that is felt as a site which is fine at low traffic and poor at higher.
Raise it towards the working set, leaving room for everything else on the machine. On a server that also runs the web application, taking too much is worse than taking too little, because memory pressure produces swapping and swapping is far slower than the disk reads you were avoiding.
Keep it reachable only where it needs to be
A database on a machine you control is frequently more exposed than one on shared hosting, because nobody configured a restriction.
ss -tlnp | grep -E '3306|5432'
mysql -e "SELECT user, host FROM mysql.user WHERE host NOT IN ('localhost','127.0.0.1')"
mysql -e "SELECT user, host FROM mysql.user WHERE authentication_string = '' OR authentication_string IS NULL"
Binding to the local interface removes the question entirely when the application runs on the same machine, which is the common case. Where remote access is genuinely needed, an encrypted tunnel is simpler to reason about than an exposed port with an address list.
The last command finds accounts with no password. On a database installed from a package and never hardened, that list is occasionally not empty. Managing MySQL and remote database access deals with the panel side.