SCALING
August 5, 2026

How to Set Up a Separate Database Server

5 min read
Author
CloudStick Team
Security Specialist
Share this article
How to Set Up a Separate Database Server
CloudStick
Split Your
Database Off

Why Separate the Database From the App Server

On a single-server setup, MariaDB shares CPU, RAM, and disk I/O with Nginx and PHP-FPM on every request. Under normal traffic that is fine, but the moment either side spikes, they steal resources from each other: a slow query holds a CPU core that PHP-FPM needed to spawn a worker, and a burst of PHP-FPM workers writing session data competes with MySQL for the same disk queue. The symptoms rarely say "resource contention" directly, they just show up as random slowness that is hard to pin on either service.

top -bn1 | head -15
mysqladmin status
# if mysqld and php-fpm workers are both pegging CPU/iowait at once,
# they are actively competing for the same box

Moving MariaDB to its own server removes that competition entirely, and it unlocks independent sizing: a database server usually benefits from more RAM (to hold more of the working set in the buffer pool) and faster disk (NVMe over SATA SSD) than the app server needs, while the app server can stay leaner since it no longer has to reserve headroom for MySQL. Once you outgrow a single app server and start scaling horizontally, a dedicated database server also becomes the one thing every app server shares, instead of each app server carrying its own out-of-sync copy of the data.

Provisioning and Securing the New DB Server

Provision a new Ubuntu 22.04 server sized for your working set and install MariaDB 10.6 as a normal system package, the same way it already runs on your current app server. Then, before you touch any data, lock the network side down. The two changes that matter are the MySQL bind-address and the firewall — get these wrong and you have a database server answering to the public internet instead of just your app server.

sudo apt update && sudo apt install mariadb-server
# /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
bind-address = 10.0.1.20 # the DB server's private/internal IP only
sudo systemctl restart mariadb
# firewall: only the app server's IP may reach port 3306
sudo ufw allow from 10.0.1.10 to any port 3306 proto tcp
sudo ufw deny 3306

Port 3306 should never be reachable from the public internet, period. A database with an open port and a weak password is a matter of when, not if, it gets scanned and hit — bind it to the private network, allow only the app server's IP through the firewall, and treat any other configuration as a breach waiting to happen.

If both servers are already connected to the same CloudStick account, you do not need to hand-roll database users over SSH either. Add the new server to CloudStick and use the Visual Database Manager to create the database and a restricted-privilege user for it directly from the dashboard — the same per-site isolation CloudStick applies locally carries over to the dedicated server, without opening a terminal or installing phpMyAdmin.

Migrating the Data Safely With mysqldump

For most WordPress and small-to-medium application databases, mysqldump is the simplest reliable path: a consistent logical export from the old server, piped straight over SSH into the new one so the data never touches an unencrypted intermediate file.

# on the current app server, export and stream directly to the new DB server
mysqldump --single-transaction --quick --routines --triggers \
-u root -p sitedb | ssh user@10.0.1.20 \
"mysql -u root -p sitedb"
# or export to a compressed file first, for very large databases
mysqldump --single-transaction --quick sitedb | gzip > sitedb.sql.gz
scp sitedb.sql.gz user@10.0.1.20:/tmp/
gunzip -c /tmp/sitedb.sql.gz | mysql -u root -p sitedb

--single-transaction keeps InnoDB tables consistent without locking writes on the source, so a live site keeps serving traffic during the export. For databases running into tens of gigabytes, mysqldump's runtime and the size of the resulting file both become a problem — at that scale a physical copy is faster and more predictable: stop writes briefly, rsync the MariaDB data directory (/var/lib/mysql) to the new server, and start MariaDB there instead of replaying a logical dump row by row.

Pointing the App to the New Host

Once the data is on the new server and verified, the app only needs one change: swap the database host from localhost to the new server's private IP. For WordPress that means wp-config.php; for most other frameworks it is a DB_HOST value in .env.

// wp-config.php
define( 'DB_HOST', '10.0.1.20' );
# .env
DB_HOST=10.0.1.20
DB_PORT=3306

Always use the private/internal IP here, never the public one — even though the firewall in the previous step already blocks outside traffic, routing legitimate app traffic over the private network keeps it off the public interface entirely and avoids any egress bandwidth charges some providers apply to public-IP traffic between servers in the same region.

Testing and Verifying Before Cutover

Before you send real traffic at the new configuration, confirm the app server can actually reach the database server on the private network and that the credentials work from that direction — not just from localhost on the DB server itself.

# from the app server, not the DB server
mysql -h 10.0.1.20 -u sitedb_user -p -e "SELECT 1;"
# confirm row counts match on both sides before you cut over
mysql -h 10.0.1.20 -u root -p -e "SELECT COUNT(*) FROM sitedb.wp_posts;"

Load the site in a staging copy or a maintenance window and click through the paths that hit the database hardest — search, checkout, admin list views — and watch query latency, since a network hop that adds even a few milliseconds per query can add up across a page that fires dozens of queries. Compare CPU, RAM, and disk I/O on both servers before and after the cutover; if you already have both servers connected under the same CloudStick account, the Server panel gives you those live graphs side by side without SSHing into either box, which makes it easy to confirm the app server's load actually dropped and the new database server is comfortably within its headroom.

Decommissioning the Old Local Database

Do not drop the old database the moment the site loads correctly against the new host. Run on the new server for at least a few days — through your normal traffic and backup cycle — before removing anything from the app server.

# once you have confirmed a stable run on the new DB server:
mysqldump -u root -p sitedb | gzip > sitedb-final-local-backup.sql.gz
mysql -u root -p -e "DROP DATABASE sitedb;"
sudo systemctl disable --now mariadb # on the app server only

Keep a final compressed dump of the old local database somewhere outside the app server as a rollback point, then drop the database and stop MariaDB on the app server so it stops consuming RAM and CPU it no longer needs. To recap the whole move: provision and secure the new box first (bind-address on the private IP, firewall limited to the app server's IP), migrate with mysqldump or a physical copy depending on size, point wp-config.php or .env at the new private IP, verify connectivity and performance under real traffic, and only then retire the local instance. With both servers on the same CloudStick account, you get the Visual Database Manager for user and permission changes and the Server panel for monitoring both boxes through the migration and afterward, so the dedicated database server is just one more managed server rather than a separate system to babysit.

Leave a comment
Full Name
Email Address
Message
Contents