Installing MySQL on Ubuntu: Practical Steps for Reliable Database Operations
Production workloads rely on consistent, predictable MySQL deployments. Automated provisioning tools make the process simple, but knowing the sequence reveals what can go wrong and where you can intervene for security or tuning. Here’s a battle-tested walkthrough using Ubuntu 20.04 LTS and MySQL 8.0, without abstraction layers or transient containers.
Why Install Manually?
- Direct access to base configuration (
/etc/mysql/
) - No abstraction—see exactly what systemd does, how users and permissions are handled, and which defaults ship with the OS package
- Required for edge case debugging (package drift, service failovers, migration scenarios)
1. Preparation and System Update
Before touching MySQL, update everything—stale packages are the fastest way to end up troubleshooting dependencies.
sudo apt update
sudo apt upgrade -y
Reboots can be necessary after kernel or library updates (sudo reboot
). Omit at your own risk; pending reboots can block service starts.
2. Install MySQL Server
Ubuntu 20.04+ defaults to MySQL 8.0 in its package repositories. Pin a version if consistency is critical across environments.
sudo apt install mysql-server=8.0.36-0ubuntu0.20.04.1 -y
The =version
pin prevents silent upgrades in the future—essential in CI/CD or if testing for minor-release regressions.
3. Confirm Service Health
Check the status immediately. A failed start often surfaces most dependency or configuration issues early.
sudo systemctl status mysql
Sample healthy output:
● mysql.service - MySQL Community Server
Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
Active: active (running) since ...
If you see Active: failed
, export journal logs right away:
sudo journalctl -xeu mysql
Look for messages about permission issues (AppArmor, SELinux, disk full).
4. Initial Hardening (mysql_secure_installation
)
Don’t skip this. MySQL's install script defaults are insecure—root user with no password, anonymous users, wide-open test database. The hardening script steps through these risks.
sudo mysql_secure_installation
Gotcha: Enabling the VALIDATE PASSWORD COMPONENT
is wise in production (enforces password complexity), but it’s often too restrictive for throwaway dev databases.
Typical questions:
- Set up password validation? (recommended: yes)
- Remove anonymous users? (always yes)
- Disallow root login remotely? (yes for anything outside a cluster)
- Remove test database? (eliminate)
- Reload privilege tables now? (apply changes immediately)
5. Local Root Access and Auth Plugins
Since MySQL 5.7, Ubuntu’s package sometimes configures the root
account to use auth_socket
(Linux auth), which blocks password login. To revert to standard password-based access:
sudo mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'YourStrongPassword!';
FLUSH PRIVILEGES;
EXIT;
Check plugin status:
SELECT user, host, plugin FROM mysql.user;
6. Create Application Database and User
Never use root
for apps. Always assign the minimum required privileges.
Example: application called “inventorysvc”.
CREATE DATABASE inventorydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'inventorysvc'@'localhost' IDENTIFIED BY 'G43rmvF_pTq9w2!z';
GRANT ALL PRIVILEGES ON inventorydb.* TO 'inventorysvc'@'localhost';
FLUSH PRIVILEGES;
Note: For remote access, swap 'localhost'
for an IP or %
, but restrict by firewall as well.
7. Quick Validation
Test authentication and privilege separation:
mysql -u inventorysvc -p inventorydb
Then in SQL:
SHOW TABLES;
Should return Empty set
unless your application already migrated its schema.
Troubleshooting Real Failures
- MySQL won’t start after install
Errcode: 13 - Permission denied
— AppArmor/SELinux blocks. Check/var/log/mysql/error.log
and profile enforcement status.
- Can’t log in as root
- Typical message:
Solution: check authentication plugin and possibly reset method as outlined above.ERROR 1698 (28000): Access denied for user 'root'@'localhost'
- Typical message:
Known issue: Unattended upgrades may restart MySQL and apply minor changes; pin versions using apt-mark hold mysql-server
if uptime and version stability are paramount.
Summary Table of Essential Commands
Command | Description |
---|---|
sudo apt update && sudo apt upgrade -y | Update repositories and packages |
sudo apt install mysql-server=8.0.36-... -y | Install/pin exact MySQL version |
sudo systemctl status mysql | Check MySQL service health |
sudo systemctl enable --now mysql | Enable and start at boot |
sudo mysql_secure_installation | Harden the default configuration |
sudo mysql -u root -p | Access MySQL with password auth |
mysql -u [user] -p [database] | App user login for connectivity testing |
Final Notes
A manual install process may feel old-school, but when you hit subtle edge cases—permissions, plugin misalignment, package conflicts—it’s the only way to gain full control. Alternatives like MariaDB or Percona can be swapped in with similar procedure but watch for subtle defaults. Finally: always back up /etc/mysql/
and /var/lib/mysql/
before any experimental reconfiguration.
For larger deployments, automate these steps with Ansible or Terraform, but keep the fundamentals clear—unexpected breakage still requires shell access and logs.
If you need high-availability (native replication, group replication, or ProxySQL), baseline installs like the above are necessary precursors. Failure to lock down a new MySQL node means more effort cleaning up after lateral movement or data breaches—address it early.