As your application or website grows, there may come a point where you’ve outgrown your current server setup. If you are hosting your web server and database backend on the same machine, it may be a good idea to separate these two functions so that each can operate on its own hardware and share the load of responding to your visitors’ requests.
In this guide, we’ll go over how to configure a remote MySQL database server that your web application can connect to. We will use WordPress as an example in order to have something to work with, but the technique is widely applicable to any application backed by MySQL.
Before beginning this tutorial, you will need:
Having one’s data stored on a separate server is a good way to expand gracefully after hitting the performance ceiling of a one-machine configuration. It also provides the basic structure necessary to load balance and expand your infrastructure even more at a later time. After installing MySQL by following the prerequisite tutorial, you’ll need to change some configuration values to allow connections from other computers.
Most of the MySQL server’s configuration changes can be made in the mysqld.cnf
file, which is stored in the /etc/mysql/mysql.conf.d/
directory by default. Open up this file on your database server with root privileges in your preferred editor. Here, we’ll use nano
:
This file is divided into sections denoted by labels in square brackets ([
and ]
). Find the section labeled mysqld
:
. . .
[mysqld]
. . .
Within this section, look for a parameter called bind-address
. This tells the database software which network address to listen for connections on.
By default, this is set to 127.0.0.1
, meaning that MySQL is configured to only look for local connections. You need to change this to reference an external IP address where your server can be reached.
If both of your servers are in a datacenter with private networking capabilities, use your database server’s private network IP. Otherwise, you can use its public IP address:
[mysqld]
. . .
bind-address = db_server_ip
Because you’ll connect to your database over the internet, it’s recommended that you require encrypted connections to keep your data secure. If you don’t encrypt your MySQL connection, anybody on the network could sniff sensitive information between your web and database servers. To encrypt MySQL connections, add the following line after the bind-address
line you just updated:
[mysqld]
. . .
require_secure_transport = on
. . .
Save and close the file when you are finished. If you’re using nano
, do this by pressing CTRL+X
, Y
, and then ENTER
.
For SSL connections to work, you will need to create some keys and certificates. MySQL comes with a command that will automatically set these up. Run the following command, which creates the necessary files. It also makes them readable by the MySQL server by specifying the UID of the mysql user:
To force MySQL to update its configuration and read the new SSL information, restart the database:
To confirm that the server is now listening on the external interface, run the following netstat
command:
Outputtcp 0 0 db_server_ip:3306 0.0.0.0:* LISTEN 27328/mysqld
netstat
prints statistics about your server’s networking system. This output shows us that a process called mysqld
is attached to the db_server_ip
at port 3306
, the standard MySQL port, confirming that the server is listening on the appropriate interface.
Next, open up that port on the firewall to allow traffic through:
Those are all the configuration changes you need to make to MySQL. Next, we will go over how to set up a database and some user profiles, one of which you will use to access the server remotely.
Even though MySQL itself is now listening on an external IP address, there are currently no remote-enabled users or databases configured. Let’s create a database for WordPress, and a pair of users that can access it.
Begin by connecting to MySQL as the root MySQL user:
Note: If you have password authentication enabled, as described in Step 3 of the prerequisite MySQL tutorial, you will instead need to use the following command to access the MySQL shell:
After running this command, you will be asked for your MySQL root password and, after entering it, you’ll be given a new mysql>
prompt.
From the MySQL prompt, create a database that WordPress will use. It may be helpful to give this database a recognizable name so that you can easily identify it later on. Here, we will name it wordpress
:
Now that you’ve created your database, you next need to create a pair of users. We will create a local-only user as well as a remote user tied to the web server’s IP address.
First, create your local user, wpuser, and make this account only match local connection attempts by using localhost in the declaration:
Then grant this account full access to the wordpress
database:
This user can now do any operation on the database for WordPress, but this account cannot be used remotely, as it only matches connections from the local machine. With this in mind, create a companion account that will match connections exclusively from your web server. For this, you’ll need your web server’s IP address.
Please note that you must use an IP address that utilizes the same network that you configured in your mysqld.cnf
file. This means that if you specified a private networking IP in the mysqld.cnf
file, you’ll need to include the private IP of your web server in the following two commands. If you configured MySQL to use the public internet, you should match that with the web server’s public IP address.
After creating your remote account, give it the same privileges as your local user:
Lastly, flush the privileges so MySQL knows to begin using them:
Then exit the MySQL prompt by typing:
Now that you’ve set up a new database and a remote-enabled user, you can move on to testing whether you’re able to connect to the database from your web server.
Before continuing, it’s best to verify that you can connect to your database from both the local machine — your database server — and from your web server.
First, test the local connection from your database server by attempting to log in with your new account:
When prompted, enter the password that you set up for this account.
If you are given a MySQL prompt, then the local connection was successful. You can exit out again by typing:
Next, log into your web server to test remote connections:
You’ll need to install some client tools for MySQL on your web server in order to access the remote database. First, update your local package cache if you haven’t done so recently:
Then install the MySQL client utilities:
Following this, connect to your database server using the following syntax:
Again, you must make sure that you are using the correct IP address for the database server. If you configured MySQL to listen on the private network, enter your database’s private network IP. Otherwise, enter your database server’s public IP address.
You will be asked for the password for your remotewpuser account. After entering it, and if everything is working as expected, you will see the MySQL prompt. Verify that the connection is using SSL with the following command:
If the connection is indeed using SSL, the SSL:
line will indicate this, as shown here:
Output--------------
mysql Ver 14.14 Distrib 5.7.18, for Linux (x86_64) using EditLine wrapper
Connection id: 52
Current database:
Current user: remotewpuser@203.0.113.111
SSL: Cipher in use is DHE-RSA-AES256-SHA
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.7.18-0ubuntu0.16.04.1 (Ubuntu)
Protocol version: 10
Connection: 203.0.113.111 via TCP/IP
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3306
Uptime: 3 hours 43 min 40 sec
Threads: 1 Questions: 1858 Slow queries: 0 Opens: 276 Flush tables: 1 Open tables: 184 Queries per second avg: 0.138
--------------
After verifying that you can connect remotely, go ahead and exit the prompt:
With that, you’ve verified local access and access from the web server, but you have not verified that other connections will be refused. For an additional check, try doing the same thing from a third server for which you did not configure a specific user account in order to make sure that this other server is not granted access.
Note that before running the following command to attempt the connection, you may have to install the MySQL client utilities as you did above:
This should not complete successfully, and should throw back an error that looks similar to this:
OutputERROR 1130 (HY000): Host '203.0.113.12' is not allowed to connect to this MySQL server
This is expected, since you haven’t created a MySQL user that’s allowed to connect from this server, and also desired, since you want to be sure that your database server will deny unauthorized users access to your MySQL server.
After successfully testing your remote connection, you can proceed to installing WordPress on your web server.
To demonstrate the capabilities of your new remote-capable MySQL server, we will go through the process of installing and configuring WordPress — the popular content management system — on your web server. This will require you to download and extract the software, configure your connection information, and then run through WordPress’s web-based installation.
On your web server, download the latest release of WordPress to your home directory:
Extract the files, which will create a directory called wordpress
in your home directory:
WordPress includes a sample configuration file which we’ll use as a starting point. Make a copy of this file, removing -sample
from the filename so it will be loaded by WordPress:
When you open the file, your first order of business will be to adjust some secret keys to provide more security to your installation. WordPress provides a secure generator for these values so that you do not have to try to come up with good values on your own. These are only used internally, so it won’t hurt usability to have complex, secure values here.
To grab secure values from the WordPress secret key generator, type:
This will print some keys to your output. You will add these to your wp-config.php
file momentarily:
Warning! It is important that you request your own unique values each time. Do not copy the values shown here!
Outputdefine('AUTH_KEY', 'L4|2Yh(giOtMLHg3#] DO NOT COPY THESE VALUES %G00o|te^5YG@)');
define('SECURE_AUTH_KEY', 'DCs-k+MwB90/-E(=!/ DO NOT COPY THESE VALUES +WBzDq:7U[#Wn9');
define('LOGGED_IN_KEY', '*0kP!|VS.K=;#fPMlO DO NOT COPY THESE VALUES +&[%8xF*,18c @');
define('NONCE_KEY', 'fmFPF?UJi&(j-{8=$- DO NOT COPY THESE VALUES CCZ?Q+_~1ZU~;G');
define('AUTH_SALT', '@qA7f}2utTEFNdnbEa DO NOT COPY THESE VALUES t}Vw+8=K%20s=a');
define('SECURE_AUTH_SALT', '%BW6s+d:7K?-`C%zw4 DO NOT COPY THESE VALUES 70U}PO1ejW+7|8');
define('LOGGED_IN_SALT', '-l>F:-dbcWof%4kKmj DO NOT COPY THESE VALUES 8Ypslin3~d|wLD');
define('NONCE_SALT', '4J(<`4&&F (WiK9K#] DO NOT COPY THESE VALUES ^ZikS`es#Fo:V6');
Copy the output you received to your clipboard, then open the configuration file in your text editor:
Find the section that contains the dummy values for those settings. It will look something like this:
. . .
define('AUTH_KEY', 'put your unique phrase here');
define('SECURE_AUTH_KEY', 'put your unique phrase here');
define('LOGGED_IN_KEY', 'put your unique phrase here');
define('NONCE_KEY', 'put your unique phrase here');
define('AUTH_SALT', 'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT', 'put your unique phrase here');
define('NONCE_SALT', 'put your unique phrase here');
. . .
Delete those lines and paste in the values you copied from the command line.
Next, enter the connection information for your remote database. These configuration lines are at the top of the file, just above where you pasted in your keys. Remember to use the same IP address you used in your remote database test earlier:
. . .
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');
/** MySQL database username */
define('DB_USER', 'remotewpuser');
/** MySQL database password */
define('DB_PASSWORD', 'password');
/** MySQL hostname */
define('DB_HOST', 'db_server_ip');
. . .
And finally, anywhere in the file, add the following line which tells WordPress to use an SSL connection to our MySQL database:
define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL);
Save and close the file.
Next, copy the files and directories found in your ~/wordpress
directory to Nginx’s document root. Note that this command includes the -a
flag to make sure all the existing permissions are carried over:
After this, the only thing left to do is modify the file ownership. Change the ownership of all the files in the document root over to www-data, Ubuntu’s default web server user:
With that, WordPress is installed and you’re ready to run through its web-based setup routine.
WordPress has a web-based setup process. As you go through it, it will ask a few questions and install all the tables it needs in your database. Here, we will go over the initial steps of setting up WordPress, which you can use as a starting point for building your own custom website that uses a remote database backend.
Navigate to the domain name (or public IP address) associated with your web server:
http://example.com
You will see a language selection screen for the WordPress installer. Select the appropriate language and click through to the main installation screen:
Once you have submitted your information, you will need to log into the WordPress admin interface using the account you just created. You will then be taken to a dashboard where you can customize your new WordPress site.
By following this tutorial, you’ve set up a MySQL database to accept SSL-protected connections from a remote Wordpress installation. The commands and techniques used in this guide are applicable to any web application written in any programming language, but the specific implementation details will differ. Refer to your application or language’s database documentation for more information.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
To clarify, as far as MYSQL is concerned wordpressuser@localhost and wordpressuser@web_server_ip are different users?
Hello @Nuwanda!
Yes, the two are indeed separate users, although I can see how having two different users with the same name might be confusing. I’ve updated the tutorial to make it clearer that they’re two different user profiles by renaming them
wpuser@localhost
andremotewpuser@localhost
.Nicely put together - thanks for this!
One nice addition - if you add your database server’s IP address to the /etc/hosts file on your web server with a name, you can use that name instead of the IP address in your configuration files (esp nice if you have more than one wordpress or other database-driven installation). Then if you move your databases to a different server, you only have one place to change the IP.
You’re absolutely right! Adding the database server’s IP address to the
/etc/hosts
file on your web server with a custom name is a smart and convenient solution, especially when managing multiple WordPress or database-driven installations. This approach makes it much easier to handle future server migrations or changes without having to update the IP address in multiple configuration files.Regards
This is really help full as I was trying to optimize my site by making its database to a remote one.
I’m glad you found the information helpful! Moving your database to a remote server is a great way to optimize performance, especially for resource-intensive sites. It reduces the load on your web server and can significantly improve scalability.
You can also check this question that was asked in our comminityL
https://www.digitalocean.com/community/questions/how-to-tweak-mysql-mariadb-configuration-for-increased-performance-and-stability
Regards
Unfortunately, I run into a problem while following this tutorial: SSL will not enable for mysql:
This is the following output from the netstat command:
This is after I have followed each instruction in Step 1, before getting to Step 2.
------ UPDATE ------- I found
bind-address = 0.0.0.0
in two locations on the mysqld.cnf file: in the middle and at the end! My output for the netstat command is now correct with IP address showing with port 3306 but still same output formysql status
I had this issue too. But eventually resolved it, what I did was a little different.
I recreated my DB droplet and I followed all the steps but skipped the SSL steps. Skipping the:
and the
parts.
After I got to the part of confirming the connection on my app server, I went back and did the above SSL parts and now I see the IP address with port 3306 & also the
part
I’m glad that you’ve sorted this! Also thanks for sharing what the issue was and how you were able to solve it! This can definitely help others if they run into the same case scenario.
Regards
Nice catch here!
It’s always a good idea to double check the configuration files and inspect for any typos or misconfigured values.
Check that the the certificates are not expired or invalid by checking them with OpenSSL:
You can review the MySQL error log for clues:
Regards
How would I go about accessing the mysql database with something like Sequel Pro after doing this?
Heya, Tim
You can check this article from Sequal Pro’s docs:
https://sequelpro.com/docs/get-started/get-connected/remote
On another note you can use MySQL WorkBench:
https://www.digitalocean.com/community/tutorials/how-to-connect-to-a-mysql-server-remotely-with-mysql-workbench
Regards
Hi, How do I connect to the db from MySQL Workbench after doing this?
You should be able to connect via a SSH Tunnel with a localhost mysql user.
Heya, @hasantha
You can check this article as well:
https://www.digitalocean.com/community/tutorials/how-to-connect-to-a-mysql-server-remotely-with-mysql-workbench
Regards
Awesome tutorial
Is there anyone who would know why the wordpress installation takes this long?
its been over 2 hours now after i pressed “install wordpress” when i visit the site on another tab I’m redirected to the installation page again
Heya,
WordPress needs the correct file and directory permissions to write to its configuration files and database. If permissions are incorrect, the
wp-config.php
file might not be created, or the installation cannot proceed.If the database details provided during the setup are incorrect or the database server is slow to respond, the installation process may fail or loop.
wp-config.php
file (if it exists).Your browser might cache the installation page, making it seem like the installation is stuck.
Hope that this helps!
Can I setup WP Multisite & Multitenant using this configuration?
Yes, you can set up a WordPress Multisite and potentially a multitenant configuration using the setup described in the tutorial. The remote database approach works well for both scenarios, as WordPress Multisite relies heavily on database interactions. However, there are some considerations and adjustments you might need to make to optimize this setup for a multisite or multitenant environment.
max_connections
,query_cache_size
, etc.) to handle multisite traffic due to the fact that multisite increases the number of database queries due to multiple sites operating simultaneously.Regards
Hi I am and have been working on this tutorial and I am trying to get my Webserver like instructed in (Step 3 — Testing Remote and Local Connections) to listen (or connect to my) remote database I set up but I am get the above error
I’m over here loosing it… any help would be awesome…
for the bind address i used my private ip for that since both droplets are DigitalOceans but should I have gone with public address for bind?
Heya,
You can confirm the
bind-address
in MySQL Configuration**: Open the MySQL configuration file (usually/etc/mysql/mysql.conf.d/mysqld.cnf
or/etc/my.cnf
depending on your MySQL installation):Ensure the
bind-address
is set to the private IP of the database droplet:Save the file and restart MySQL:
If UFW (Uncomplicated Firewall) is active on the database droplet, ensure it allows traffic on port 3306 (MySQL’s default port) from the web server’s private IP.
Reload the firewall:
Test connectivity between the web server and database droplet using the private IP.
From the web server droplet, run:
Or use
telnet
to check the MySQL port:If the connection fails, ensure private networking is enabled on both droplets in the same VPC and region.
Ensure the MySQL user on the database droplet is configured to allow access from the web server’s private IP.
Log in to MySQL on the database droplet:
Check the user’s host permissions:
If the user is set to
localhost
, update it to allow access from the web server’s private IP:On the web server, ensure your application is using the correct credentials and private IP of the database droplet in its database configuration file.
Example for a
.env
file in Laravel:If you’re still facing issues, check the MySQL logs on the database droplet for detailed error messages:
Or in the MySQL error log, typically located at
/var/log/mysql/error.log
.Hope that this helps!
Don’t forget this command, it. saved me lot of headaches… sudo ufw allow mysql
Yes, the command is included in the article!
Thanks, Victor!
This is a really helpful tutorial, thank you. I’m not using wordpress for what I’m building and so it would be really great if you could add to the above - even if its just a link on where to get started - for using the same architecture for users who are not working with wordpress and who want to use webforms to securely submit data to their database.
Heya,
I’m glad you’ve found this tutorial useful! As for the webforms you can use a lightweight web framework such as Django (Python), Flask (Python), Laravel (PHP), or Node.js with Express. These frameworks provide tools to create and manage secure web forms.
And for the database you can use MySQL, PostgreSQL, or another relational database, connecting securely using the selected framework’s ORM or direct SQL queries.
Regards
Hi Everyone,
All was coming alright as I followed this tutorial but got stack just after this step: mysql -u remote_user -h my_db_server_ip -p
I got the following error: ERROR 2003 (HY000): Can’t connect to MySQL server on ‘db_server_ip’ (111)
Any advise will be highly appreciated.
Best regards, Thebe
Ok This was caused by me changing the port from 3306 to 25060 in /etc/mysql/mysql.conf.d/mysqld.cnf
I just wanted to use a different port like DO :)
Heya,
I’m glad you’ve sorted this. Also make sure the new port is whitelisted in Firewall configuration to prevent issues.
Regards
Good article! I’d strongly recommend only opening the MySQL port to your web_server_ip rather than everyone.
It’s a best practice to restrict access to your MySQL server to only trusted IP addresses, such as your web server’s IP, to enhance security. Allowing unrestricted access to MySQL (port 3306) from any IP can leave your database vulnerable to unauthorized access, which is a significant security risk.
Regards