To set up MySQL on a Linux server, update your packages, install the MySQL Server package (APT/DNF), start and enable the mysqld service, run mysql_secure_installation, create a database with a least-privileged user, adjust bind-address and firewall (port 3306), and verify local and remote connections. The steps below cover Ubuntu, RHEL/CentOS, and more.
In this guide, you’ll learn how to setup MySQL on Linux server securely and efficiently, from installation to hardening, configuration, remote access, backups, and basic performance tuning. I’ll share practical steps I use in production environments, with distro-specific commands for Ubuntu/Debian and RHEL/CentOS/Rocky/AlmaLinux, plus troubleshooting tips to keep your database running reliably.
Understand Your Options: Repositories and Versions
Before you install, decide where MySQL should come from. Your choice affects version availability, defaults, and update cadence.
- Distribution repository: Easiest path on Ubuntu LTS. On Debian and some RHEL derivatives, the default “mysql-server” can be MariaDB. Stable and well-integrated with the OS.
- Official MySQL Community repository: Provides the latest MySQL 8 (including LTS 8.4). Recommended if you need current features, InnoDB performance improvements, or consistent behavior across distros.
- MariaDB as an alternative: Drop-in for many workloads, but not identical to MySQL 8. Choose deliberately; mixing features/plugins later can be complex.
Prerequisites and Planning
- Root/sudo access on the server.
- Supported OS: Ubuntu 20.04/22.04/24.04, Debian 12, RHEL/CentOS/Rocky/AlmaLinux 8/9.
- Resources: At least 1–2 GB RAM for small deployments; more for production.
- Firewall: Allow TCP 3306 only for trusted IPs.
- Hostname/timezone: Correct time (NTP) and hostname improve logs and replication.
- Backup location: Separate disk or bucket for dumps/snapshots.
Install MySQL on Popular Linux Distributions
Ubuntu (LTS) and Debian
On Ubuntu LTS, installing from the default repo typically yields MySQL 8 Community Server. Debian may install MariaDB when you run mysql-server; if you specifically want Oracle MySQL, use the official apt repository.
# Ubuntu LTS: install from Ubuntu repo (simple path)
sudo apt update
sudo apt install -y mysql-server
sudo systemctl enable --now mysql.service
# Debian/Ubuntu: install from official MySQL APT repo (for latest MySQL 8.x)
wget https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.29-1_all.deb
# During the prompt, select MySQL Server 8.x (or 8.4 LTS), then:
sudo apt update
sudo apt install -y mysql-server
sudo systemctl enable --now mysql.service
On some Ubuntu builds, the root user may authenticate via the auth_socket plugin (no password for local root shell). We’ll standardize this shortly with mysql_secure_installation.
RHEL/CentOS/Rocky/AlmaLinux
On Enterprise Linux, the official MySQL Yum repository is the most consistent way to get MySQL 8.
# Enable MySQL Community 8 repo (EL8/EL9 choose the matching package)
# Example for EL9:
sudo dnf install -y https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm
sudo dnf install -y mysql-community-server
sudo systemctl enable --now mysqld
# Find the temporary root password (initial install)
sudo grep 'temporary password' /var/log/mysqld.log
Note: On first start, MySQL from the Yum repo generates a temporary root password logged in /var/log/mysqld.log.
openSUSE (optional)
sudo zypper refresh
sudo zypper install -y mysql-community-server
sudo systemctl enable --now mysqld
Secure the MySQL Installation
Run the built-in hardening script. It sets a root password (or reconfigures auth), removes test data, and tightens defaults.
sudo mysql_secure_installation
- Set/validate root password: Use a strong, unique passphrase.
- Remove anonymous users: Yes.
- Disallow remote root login: Yes (recommended).
- Remove test database: Yes.
- Reload privilege tables: Yes.
Next, create an application database and a least-privileged user.
# Log in as root (password or socket, depending on your install)
sudo mysql -u root -p
-- Inside MySQL shell:
CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'StrongPassw0rd!';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Open the Firewall Carefully
Only expose port 3306 to trusted IPs or private subnets. Avoid binding MySQL to the public internet unless absolutely necessary.
# UFW (Ubuntu)
sudo ufw allow from 203.0.113.10 to any port 3306 proto tcp
sudo ufw reload
# firewalld (RHEL/CentOS/Rocky/Alma)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10/32" port protocol="tcp" port="3306" accept'
sudo firewall-cmd --reload
Enable Local and Remote Connections
By default, many installs bind to localhost only. To accept remote connections (from a specific app server, for example), adjust the bind-address and create a remote user with limited scope.
# Debian/Ubuntu config path
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
# RHEL-based config path
sudo nano /etc/my.cnf
# Set inside [mysqld] (choose one):
bind-address = 0.0.0.0 # listens on all interfaces (use firewall!)
# or
bind-address = 10.0.0.5 # listen only on private IP
# Then restart:
sudo systemctl restart mysql # Debian/Ubuntu
sudo systemctl restart mysqld # RHEL-based
# Create a remote user allowed only from the app server IP
sudo mysql -u root -p
CREATE USER 'appuser'@'203.0.113.10' IDENTIFIED BY 'StrongPassw0rd!';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'203.0.113.10';
FLUSH PRIVILEGES;
EXIT;
Test locally and remotely:
# Local test
mysql -u appuser -p -e "SHOW DATABASES;"
# Remote test (from the allowed host)
mysql -h your.mysql.server -u appuser -p -e "SELECT 1;"
Production-Grade Configuration (my.cnf)
Fine-tune MySQL for your workload. The examples below are safe starting points for many small-to-medium deployments. Adjust using real metrics (SHOW GLOBAL STATUS, slow query log, and performance_schema).
# Debian/Ubuntu: /etc/mysql/mysql.conf.d/mysqld.cnf
# RHEL-based: /etc/my.cnf or /etc/my.cnf.d/server.cnf
[mysqld]
# Networking
bind-address = 0.0.0.0
max_connections = 200
# InnoDB (tune based on RAM; ~50–70% if DB-only server)
innodb_buffer_pool_size = 4G
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit = 1
# Logging & diagnostics
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
# Security
local_infile = OFF
skip_symbolic_links = ON
# Optional: Require TLS for remote clients (ensure certs exist)
# require_secure_transport = ON
After changes, restart MySQL and confirm they applied:
sudo systemctl restart mysql # or mysqld
mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
TLS/SSL for MySQL (Optional but Recommended)
MySQL 8 often generates self-signed certificates at install time. Verify with:
mysql -u root -p -e "SHOW VARIABLES LIKE 'have_ssl'; SHOW STATUS LIKE 'Ssl_%';"
If not present, create or install valid certs (preferred: CA-issued), set ssl_ca, ssl_cert, and ssl_key in [mysqld], then restart. Enforce encrypted client connections with require_secure_transport=ON and create users with REQUIRE SSL as needed.
Backups and Maintenance
Always keep tested backups. For small-to-medium databases, mysqldump with a single transaction is reliable and simple.
# Full logical backup
mysqldump -u root -p --single-transaction --routines --triggers --events \
--hex-blob --all-databases | gzip > /backups/mysql-$(date +%F).sql.gz
# Restore
gunzip -c /backups/mysql-2025-01-01.sql.gz | mysql -u root -p
Set a daily cron job, rotate, and copy backups off-server. For large datasets or hot backups, consider snapshotting (LVM, ZFS) or physical backup tools. Always test recovery on a staging server.
Troubleshooting: Quick Checklist
- Service state:
systemctl status mysqlorsystemctl status mysqld. - Logs:
journalctl -u mysql -e,/var/log/mysql/error.logor/var/log/mysqld.log. - Port listening:
ss -lntp | grep 3306. - Bind address: Confirm
bind-addressmatches your intent. - Firewall/SELinux: Open 3306 to the right IPs; if changing ports on SELinux, map with
semanage port -a -t mysqld_port_t -p tcp 3307. - Authentication issues: Check auth plugins and user host entries (
SELECT user, host, plugin FROM mysql.user;).
Real-World Tips from Production
- Size buffer pool first: Memory sizing (InnoDB buffer pool) yields bigger gains than tweaking dozens of minor variables.
- Enable slow logs early: They spotlight queries to fix before scale hurts.
- Isolate workloads: If the server runs both web and DB, CPU and I/O contention can spike latency. Consider dedicated DB nodes or managed DB.
- Avoid remote root: Create explicit app users with minimal privileges and host restrictions.
- Plan upgrades: Read release notes; MySQL 8 introduces sql_mode defaults that can affect legacy schemas.
When Managed MySQL Makes Sense
If you’d rather not maintain patches, backups, and performance tuning yourself, a managed database or a fully managed VPS can help. At YouStable, we provision, secure, monitor, and back up MySQL on optimized infrastructure, so your team can focus on the app instead of the database plumbing.
FAQ: How to Setup MySQL on Linux Server
How do I reset the MySQL root password on Linux?
Stop MySQL, start it with grant tables disabled, set a new password, then restart normally. Example:
sudo systemctl stop mysql # or mysqld
sudo mysqld_safe –skip-grant-tables –skip-networking &
mysql -u root
ALTER USER ‘root’@’localhost’ IDENTIFIED BY ‘NewStrongPass!’;
FLUSH PRIVILEGES;
EXIT;
# Stop the unsafe instance, then:
sudo systemctl start mysql
What port does MySQL use and how do I open it safely?
MySQL uses TCP 3306. Open it only to specific IPs via UFW or firewalld and avoid binding to 0.0.0.0 unless necessary. For example: ufw allow from YOUR.IP.ADDR to any port 3306 proto tcp. Always restrict with security groups or VPN on cloud servers.
How do I install MySQL 8 on Debian without getting MariaDB?
Use the official MySQL APT repository. Install the mysql-apt-config package from dev.mysql.com, select MySQL Server 8.x, run apt update, then apt install mysql-server. That ensures Oracle MySQL instead of the default MariaDB packages.
How can I move the MySQL data directory to another disk?
Stop MySQL, copy the data directory with correct ownership, update datadir in the config, adjust AppArmor/SELinux contexts if enabled, and start MySQL. Validate with logs. Example paths: /var/lib/mysql to /data/mysql. Use rsync -av to preserve permissions.
What’s the easiest way to back up MySQL on Linux?
For small-to-medium instances, a nightly mysqldump --single-transaction piped to gzip is simple and effective. For larger, 24/7 systems, consider physical backups or volume snapshots and always test restores. Managed options from providers like YouStable can automate this end-to-end.
Wrap-Up
You’ve learned how to install, secure, configure, and maintain MySQL on Linux using best practices: repository choice, mysql_secure_installation, firewall rules, least-privileged users, TLS, backups, and tuning. Start small, measure, and iterate. If you outgrow DIY, YouStable can manage MySQL for you so you can focus on building great products.