
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
You need to install MySQL on Ubuntu to power a web application, but default configurations often leave databases exposed or poorly tuned for production workloads. This guide walks through installing MySQL 8.4 LTS on Ubuntu 24.04, securing the instance against common attack vectors, and validating connectivity before handing it off to developers. Before you begin, ensure your server baseline is hardened; I cover foundational OS security in my initial Ubuntu server setup guide which pairs directly with this database deployment.
sudo apt update && sudo apt install mysql-server, then execute sudo mysql_secure_installation to enforce strong authentication and remove test artifacts. Verify the service is active with systemctl status mysql and create dedicated application users instead of using the root account for production traffic.How do you install MySQL on Ubuntu 24.04 using APT?
The most reliable way to install MySQL on Ubuntu 24.04 LTS is via the official APT repositories. Ubuntu 24.04 ships with MySQL 8.4 LTS, which receives long-term support and security patches through 2029. Avoid adding third-party PPAs unless you have a specific version requirement that the official repos cannot satisfy; mixing sources is a frequent cause of dependency breakage during future upgrades.
Update package indexes and install the server
Always refresh your local package metadata before installing database software to avoid pulling outdated binaries with known vulnerabilities.
sudo apt update
sudo apt install -y mysql-server The -y flag auto-confirms the installation. On a minimal Ubuntu server image, this pulls approximately 180 MB of dependencies including libaio1, mecab, and the client utilities. The service starts automatically after installation completes.
Verify the service is running
Confirm systemd has started MySQL and that it is enabled for boot persistence:
sudo systemctl status mysql
sudo systemctl enable mysql You should see active (running) in green. If the service fails to start, check journalctl -u mysql --no-pager -n 50 for errors. Common causes include AppArmor profile conflicts or insufficient disk space on /var/lib/mysql.
How do you secure MySQL after installation on Ubuntu?
A fresh MySQL installation prioritizes usability over security. You must harden it before exposing it to any network traffic or application code. The mysql_secure_installation script handles the most critical post-install tasks interactively.
Run the security hardening script
sudo mysql_secure_installation Respond to each prompt as follows for production environments:
- VALIDATE PASSWORD COMPONENT: Press
Y. Choose strength level2(STRONG) to enforce minimum 8 characters with mixed case, numbers, and special characters. - Root password: Set a strong root password. Store it in a password manager or secrets vault immediately; never embed it in scripts.
- Remove anonymous users:
Y. Anonymous accounts allow unauthenticated access from localhost, which attackers exploit for lateral movement. - Disallow root login remotely:
Y. Root should only authenticate via Unix socket on the server itself. - Remove test database:
Y. The test database is world-readable and serves no production purpose. - Reload privilege tables:
Y. Applies all changes immediately without requiring a service restart.
Configure authentication plugin compatibility
MySQL 8.4 defaults to caching_sha2_password, which some older PHP drivers and legacy applications do not support. If your stack requires the older native authentication, create application users explicitly with the compatible plugin:
CREATE USER 'app_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Str0ng!Pass#2026';
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES; For new applications, prefer caching_sha2_password as it provides stronger cryptographic guarantees. Only fall back to native authentication when driver compatibility demands it.
How do you configure MySQL for remote access and firewall rules?
By default, MySQL binds only to 127.0.0.1, rejecting all external connections. Many tutorials instruct changing bind-address to 0.0.0.0, but this exposes the database to every network interface without discrimination. In practice, bind to a specific private IP or use UFW to restrict access at the firewall layer first.
Edit the bind address safely
Open the main configuration file:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf Locate the bind-address directive and set it to your server's private IP or keep 127.0.0.1 if applications connect locally:
# Bind to private network interface only
bind-address = 10.0.1.50 Restart MySQL to apply: sudo systemctl restart mysql.
Create application-specific users with host restrictions
Never grant remote access to root. Create dedicated users scoped to the exact source IP or subnet:
CREATE USER 'web_app'@'10.0.1.%' IDENTIFIED BY 'C0mpl3x!DbPass#24';
GRANT ALL PRIVILEGES ON production_db.* TO 'web_app'@'10.0.1.%';
FLUSH PRIVILEGES; The wildcard % in the host field allows connections from any IP in the 10.0.1.0/24 subnet. For tighter control, specify the exact application server IP.
Configure UFW firewall rules
If you followed the UFW firewall configuration guide, add MySQL access only from trusted sources:
sudo ufw allow from 10.0.1.0/24 to any port 3306 proto tcp comment 'MySQL from app subnet'
sudo ufw reload Never open port 3306 to any without an explicit allowlist. Publicly exposed MySQL instances are compromised within hours by automated scanners.
What are the essential production tuning parameters for MySQL on Ubuntu?
Default MySQL configuration assumes a development environment with minimal memory allocation. Production servers require tuning to utilize available RAM efficiently and handle concurrent connections without swapping. These settings belong in a custom override file to survive package upgrades.
Create a production override configuration
sudo nano /etc/mysql/mysql.conf.d/production-tuning.cnf Add these baseline parameters for a server with 8 GB RAM dedicated to MySQL:
[mysqld]
innodb_buffer_pool_size = 5G
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 1
max_connections = 200
thread_cache_size = 16
table_open_cache = 4000
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2 Key explanations:
- innodb_buffer_pool_size: Set to 60–70% of total RAM on a dedicated database server. This caches data and indexes in memory, reducing disk I/O dramatically.
- innodb_flush_log_at_trx_commit = 1: Ensures ACID compliance by flushing logs to disk on every commit. Only change to
2if you accept potential data loss for write performance. - slow_query_log: Captures queries exceeding 2 seconds. Review weekly to identify missing indexes or inefficient joins. Pair this with MySQL performance tuning techniques for deeper optimization.
Validate configuration before restarting
Syntax errors in MySQL config files prevent the service from starting, causing downtime. Always validate first:
sudo mysqld --validate-config
sudo systemctl restart mysql | Parameter | Development Default | Production Recommendation (8GB RAM) | Impact |
|---|---|---|---|
| innodb_buffer_pool_size | 128M | 5G | Reduces disk reads by caching hot data |
| max_connections | 151 | 200–400 | Prevents connection refused errors under load |
| innodb_log_file_size | 48M | 512M–1G | Improves write throughput for bulk operations |
| slow_query_log | OFF | ON | Enables query performance auditing |
| innodb_flush_log_at_trx_commit | 1 | 1 (or 2 for perf) | Balances durability vs. write latency |
How do you verify MySQL installation and test connectivity?
After installation and configuration, validate that MySQL accepts connections as expected and that your application credentials work correctly. Skipping this step leads to confusing application errors that mask underlying permission or network issues.
Test local root access via Unix socket
sudo mysql -u root -p On Ubuntu 24.04, root authenticates via auth_socket by default, meaning sudo mysql works without a password prompt. If you set a root password during secure installation, use -p to trigger the prompt.
Test application user connectivity
From the application server (not the database host), verify the dedicated user can connect:
mysql -u web_app -h 10.0.1.50 -p production_db If this fails, diagnose systematically:
- Check MySQL is listening on the expected interface:
ss -tlnp | grep 3306 - Verify UFW allows the source IP:
sudo ufw status verbose - Confirm user host permissions:
SELECT user, host FROM mysql.user WHERE user='web_app'; - Review MySQL error log:
sudo tail -50 /var/log/mysql/error.log
Automate health checks for monitoring
Add a simple health check script for your monitoring stack. This returns exit code 0 only if MySQL responds to queries:
#!/bin/bash
mysqladmin -u monitor_user -p'Mon!torPass24' ping >/dev/null 2>&1
exit $? Create the monitor user with minimal privileges:
CREATE USER 'monitor_user'@'localhost' IDENTIFIED BY 'Mon!torPass24';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'monitor_user'@'localhost';
FLUSH PRIVILEGES; This user cannot read or modify data, satisfying least-privilege principles while enabling uptime monitoring. Integrate this check with Prometheus, Nagios, or your preferred observability platform.
Install MySQL on Ubuntu: Next Steps for Production Readiness
You now have a functional, secured MySQL installation on Ubuntu 24.04. However, installation is only the foundation. Before going live, implement automated backups using mysqldump or Percona XtraBackup, enable TLS for encrypted connections, and establish a patching schedule aligned with Ubuntu's USN advisories. For teams managing multiple environments, consider infrastructure-as-code approaches covered in my Terraform practical guide to make database provisioning reproducible and auditable.
If your workload demands high availability, evaluate whether self-managed MySQL on EC2/VPS makes sense versus managed alternatives; I break down the cost and operational trade-offs in the RDS vs self-managed MySQL comparison. For personalized architecture review or help hardening your database layer for SOC 2 or ISO 27001 compliance, reach out directly to discuss your specific requirements.