Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Install MySQL on Ubuntu

By Kokil Thapa | Last reviewed: August 2026

To correctly install MySQL on Ubuntu for a production web application, you must go beyond the default apt install command and configure authentication, memory buffers, and security hardening specific to your workload. Whether you are deploying a high-traffic eCommerce platform or a legal-tech portal, the difference between a fragile development setup and a resilient production database lies in post-installation tuning. For developers building data-driven applications, understanding this full lifecycle is as critical as mastering database-driven website development in Nepal or any global market where reliability directly impacts revenue and user trust.

How Do You Correctly Install MySQL on Ubuntu 24.04 LTS?

The standard APT repository for Ubuntu 24.04 (Noble Numbat) ships with MySQL 8.4 LTS, which is the current long-term support release suitable for production environments in 2026. While some tutorials still reference MySQL 8.0, new deployments should target 8.4 for extended support coverage and recent performance improvements. Before running any installation commands, verify your OS version with lsb_release -a to ensure compatibility.

Installation Commands and Verification

Update your package index and install the server package. The mysql-server-8.4 metapackage pulls in all necessary dependencies including the client binaries and common libraries.

sudo apt update
sudo apt install mysql-server-8.4

# Verify the installed version
mysql --version
# Expected output: mysql  Ver 8.4.x for Linux on x86_64

# Check service status immediately after install
sudo systemctl status mysql

On Ubuntu 24.04, the MySQL service starts automatically after installation and is enabled for boot persistence. If the service fails to start, check journalctl -u mysql -n 50 --no-pager for errors related to AppArmor profiles or directory permissions. In my experience managing shared EC2 infrastructure for multiple client sites, AppArmor denials are the most common cause of startup failures after upgrades or custom path configurations.

Understanding Default Authentication Behavior

MySQL 8.4 on Ubuntu defaults to auth_socket authentication for the root user, meaning the database authenticates based on the operating system user rather than a password. This is secure for local administration but incompatible with remote connections or application drivers that expect password-based auth. You will address this during the secure installation step, but understanding this default prevents confusion when mysql -u root -p rejects passwords immediately after install.

1. apt updateRefresh package index2. apt installmysql-server-8.43. Secure InstallRoot auth + cleanup4. ConfigureBuffer pool + bind
Sequential workflow to install MySQL on Ubuntu 24.04 with mandatory security and configuration steps

What Security Steps Are Mandatory After You Install MySQL on Ubuntu?

The mysql_secure_installation script is not optional for production systems. It addresses five critical security gaps left by the default package installation. Run it immediately after the service starts:

sudo mysql_secure_installation

The interactive prompts require deliberate choices. Here is the recommended configuration for production Laravel, Symfony, or WordPress applications:

  • VALIDATE PASSWORD Component: Enable with MEDIUM strength. This enforces minimum length, mixed case, numbers, and special characters for all database passwords. For Nepal-based projects handling sensitive legal or financial data, STRONG is preferable.
  • Root Password: Set a cryptographically strong password even if you plan to keep auth_socket for local admin. Some backup tools and monitoring agents require password-based root access.
  • Remove Anonymous Users: Yes. Anonymous accounts allow unauthenticated access from localhost and are a frequent vector in compromised shared hosting environments.
  • Disallow Root Login Remotely: Yes. Administrative access should occur via SSH tunnel or sudo on the server itself. Remote root access has no legitimate production use case.
  • Remove Test Database: Yes. The test database is world-accessible by default and serves no purpose after installation.
  • Reload Privilege Tables: Yes. Changes take effect immediately without service restart.

Creating Application-Specific Database Users

Never connect your application as root. Create a dedicated user with privileges scoped to the specific database. For a Laravel application named legal_portal:

sudo mysql

CREATE DATABASE legal_portal CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'legal_app'@'localhost' IDENTIFIED BY 'Str0ng!P@ssw0rd#2026';
GRANT ALL PRIVILEGES ON legal_portal.* TO 'legal_app'@'localhost';
FLUSH PRIVILEGES;
EXIT;

The utf8mb4_unicode_ci collation is essential for Nepali Unicode content and emoji support. Using the older utf8 charset silently truncates characters outside the Basic Multilingual Plane, corrupting Devanagari text and causing subtle bugs in legal document storage. I have encountered this issue on multiple legal-tech portals where case filings contained Nepali metadata that appeared correct in the application but was corrupted at rest.

How Should You Configure MySQL Performance for Production Workloads?

The default MySQL configuration on Ubuntu assumes minimal resources and conservative safety margins. Production workloads require explicit tuning. Edit the main configuration file:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Critical Performance Parameters

These settings assume a dedicated database server with 8GB RAM running a typical Laravel or WooCommerce workload. Adjust proportionally for your hardware.

ParameterDefaultProduction Value (8GB RAM)Purpose
innodb_buffer_pool_size128M5GCaches table data and indexes in RAM. Set to 60-70% of available memory on dedicated DB servers.
innodb_log_file_size48M512MReduces checkpoint frequency for write-heavy workloads like order processing.
max_connections151300Prevents connection exhaustion under load. Monitor with SHOW STATUS LIKE 'Threads_connected'.
bind-address127.0.0.1127.0.0.1Keep localhost-only unless application servers are on separate hosts. Never bind to 0.0.0.0 without firewall rules.
slow_query_logOFFONCaptures queries exceeding threshold. Essential for identifying N+1 problems and missing indexes.
long_query_time101Threshold in seconds for slow query logging. One second catches most problematic queries without excessive noise.

After editing, validate syntax and restart:

sudo mysqld --validate-config
sudo systemctl restart mysql

A common mistake I see on client servers is setting innodb_buffer_pool_size too high on shared-memory instances, causing OOM kills during peak traffic. Always leave sufficient headroom for PHP-FPM workers, Nginx/Apache, and OS caches. On a 4GB VPS commonly used for Nepal SME projects, cap the buffer pool at 2GB maximum.

8 GB Server Memory AllocationInnoDB Buffer Pool: 5 GBTable Data + Index CachePHP-FPM Workers~1.5 GB ReservedOS + Nginx Cache~1.5 GB ReservedSafety MarginPeak Load HeadroomBackup OperationsOOM Prevention
Recommended memory allocation when you install MySQL on Ubuntu with 8GB RAM for production Laravel workloads

How Do You Integrate MySQL with Laravel and PHP Applications?

After you install MySQL on Ubuntu and complete security hardening, configure your application's database connection. Laravel 12 uses PDO with prepared statements by default, which protects against SQL injection when used correctly.

Environment Configuration

In your Laravel project's .env file:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=legal_portal
DB_USERNAME=legal_app
DB_PASSWORD=Str0ng!P@ssw0rd#2026

# Connection pooling and timeout tuning
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
DB_STRICT=true

The DB_STRICT=true setting enables strict SQL mode, which prevents silent data truncation and invalid date insertion. This is non-negotiable for legal-tech applications where data integrity is paramount. I have debugged too many production issues caused by loose mode silently accepting malformed input that later broke reporting queries or document generation.

Verifying Connectivity and Character Encoding

Run migrations and verify the connection handles Unicode correctly:

php artisan migrate:fresh --seed

# Verify character set at runtime
php artisan tinker
>>> DB::select("SHOW VARIABLES LIKE 'character_set%'");
>>> DB::select("SHOW VARIABLES LIKE 'collation%'");

If you are building APIs, follow established patterns for Laravel API best practices including proper error handling for database exceptions and connection retry logic. For teams evaluating whether to handle this infrastructure internally, understanding the ongoing maintenance burden helps inform decisions about hiring a web developer in Nepal versus managing it with existing staff.

Laravel App.env ConfigPDO DriverEloquent ORMMySQL 8.4Auth Socket/PasswordInnoDB Engineutf8mb4 CollationVerificationMigration TestUnicode InsertQuery Log CheckPrepared StmtResult Set
Application-to-database integration flow after you install MySQL on Ubuntu for Laravel projects

What Ongoing Maintenance Does MySQL Require After Installation?

Installing MySQL on Ubuntu is a one-time event; maintaining it is continuous. Production databases require proactive monitoring and scheduled maintenance to prevent degradation.

Automated Backup Strategy

Configure nightly logical backups using mysqldump or physical backups with Percona XtraBackup for larger datasets. For most Nepal-based SME projects under 50GB, mysqldump with compression is sufficient:

# /etc/cron.d/mysql-backup
0 2 * * * root mysqldump --single-transaction --routines --triggers \
  -u backup_user -p'SecureBackupPass!' legal_portal | gzip > \
  /var/backups/mysql/legal_portal_$(date +\%Y\%m\%d).sql.gz

# Retain 30 days of backups
0 3 * * * root find /var/backups/mysql -name "*.sql.gz" -mtime +30 -delete

Test restores quarterly. A backup you cannot restore is not a backup. I maintain restore runbooks for every production system I manage, because discovering corruption during an actual outage is catastrophic.

Monitoring Key Metrics

Set up alerts for these indicators before they become incidents:

  • Connections: Alert when Threads_connected exceeds 80% of max_connections.
  • Buffer Pool Hit Rate: Should stay above 99%. Below 95% indicates insufficient innodb_buffer_pool_size.
  • Slow Queries: Any spike above baseline warrants immediate investigation.
  • Disk Usage: Alert at 80% capacity. Binary logs and temporary tables can consume space unexpectedly.
  • Replication Lag: If using read replicas, lag over 5 seconds degrades user experience.

Tools like Prometheus with mysqld_exporter provide granular visibility without significant overhead. For smaller deployments, a simple cron job parsing SHOW GLOBAL STATUS output and emailing anomalies may suffice. Match monitoring complexity to operational capacity — elaborate dashboards that nobody checks are worse than simple alerts that actually get attention.

Conclusion

When you install MySQL on Ubuntu for production, treat the package installation as merely the starting point. Security hardening via mysql_secure_installation, deliberate performance tuning in mysqld.cnf, proper character encoding for multilingual content, and automated backup verification are what separate reliable production databases from fragile development setups. These steps apply whether you are deploying a legal-tech portal in Kathmandu or a SaaS platform serving global users. If you need assistance configuring MySQL for a specific workload or auditing an existing installation, reach out to discuss your project requirements.

Frequently Asked Questions

Run sudo apt update followed by sudo apt install mysql-server. This installs the latest stable MySQL version available in the official Ubuntu repositories, typically 8.0 or 8.4 LTS depending on your specific point release.

Execute sudo mysql_secure_installation immediately after setup. This interactive script removes anonymous users, disables remote root login, deletes the test database, and configures the validate_password plugin to enforce strong authentication policies for production environments.

No, the MySQL Community Server included in Ubuntu repositories is free and open source under the GPL license. You only pay for server infrastructure, typically Rs 1,500 to Rs 5,000 monthly (USD 11–37) for a basic VPS suitable for small production databases.

Laravel 12 supports both, but I recommend MySQL 8.0 or 8.4 LTS for new projects unless you have specific MariaDB requirements. MySQL has better JSON column performance and wider ecosystem support for packages like Spatie Media Library. MariaDB remains excellent for WordPress or legacy PHP applications where compatibility matters more than newer features.

Modern Ubuntu packages use auth_socket authentication by default, meaning the system root user accesses MySQL without a password. To enable password authentication, log in via sudo mysql and run ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'your_secure_password'; then flush privileges. Always use caching_sha2_password over the deprecated mysql_native_password for security.

Never use root for applications. Create a specific user with CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'strong_password'; then grant minimal permissions using GRANT SELECT, INSERT, UPDATE, DELETE ON database_name. TO 'app_user'@'localhost'; This limits damage if credentials are compromised. On legal-tech portals I build, each Laravel application gets its own restricted user rather than shared elevated access.

Check sudo systemctl status mysql.service and journalctl -xeu mysql.service for errors. Common causes include AppArmor blocking socket access, insufficient disk space in /var/lib/mysql, or corrupted InnoDB log files from interrupted installations. Verify ownership with ls -la /var/lib/mysql to ensure mysql:mysql owns all data files. I have seen this repeatedly when servers run out of space during initial package configuration.

Edit /etc/mysql/mysql.conf.d/mysqld.cnf and change bind-address from 127.0.0.1 to your private network IP or 0.0.0.0 for all interfaces. Then create a user with a specific host like 'app_user'@'192.168.1.%' instead of localhost. Always restrict firewall rules with UFW to allow port 3306 only from trusted application servers. Never expose MySQL directly to the public internet without VPN or SSH tunneling.

Set innodb_buffer_pool_size to 70% of available RAM for dedicated database servers. Configure max_connections based on your PHP-FPM worker count plus overhead, typically 150-300 for medium sites. Enable slow_query_log with long_query_time = 1 to catch performance issues early. Add character-set-server = utf8mb4 and collation-server = utf8mb4_unicode_ci for proper Unicode support. These settings prevent common bottlenecks I encounter when migrating client projects from shared hosting to VPS environments.

Run sudo apt purge mysql-server mysql-client mysql-common mysql-server-core- mysql-client-core-* to remove packages and configuration files. Then manually delete residual data with sudo rm -rf /var/lib/mysql /var/log/mysql /etc/mysql. Finally execute sudo apt autoremove to clean dependencies. Warning: this permanently destroys all databases. Always verify backups exist before running these commands on any server containing production data.

Yes, using Docker containers or manual compilation from source, though I rarely recommend this complexity for production. For development testing across versions, Docker is safest. On production servers I maintain, each application gets its own isolated VPS or uses managed database services instead of multi-version setups. The operational overhead of managing conflicting socket paths, ports, and library dependencies outweighs benefits except in specialized migration scenarios.

Use mysqldump --single-transaction --routines --triggers --all-databases > full_backup.sql for consistent logical backups without locking tables. For large production databases, consider Percona XtraBackup for physical hot backups that restore faster. Store backups outside the database server, ideally on object storage or separate volume. On client projects, I automate nightly dumps via cron and verify restoration quarterly. Never trust untested backups during upgrade windows.

This usually means auth_socket is enabled but you are connecting without sudo, or the password authentication method was changed incorrectly. First try sudo mysql to verify server access works. If it does, check the authentication plugin with SELECT user, host, plugin FROM mysql.user WHERE user='root'; If plugin shows auth_socket but you need password access, alter the user to caching_sha2_password as documented earlier. Avoid reverting to mysql_native_password unless required by legacy applications.

Use built-in commands like SHOW PROCESSLIST to see active queries, SHOW ENGINE INNODB STATUS for transaction and lock details, and query performance_schema tables for historical metrics. Enable the slow query log and analyze it with mysqldumpslow or pt-query-digest. For real-time monitoring, mysqladmin extended-status provides key buffer and thread statistics. On production Laravel applications, I pair these native tools with Laravel Debugbar during development to correlate ORM queries with actual database behavior before deployment.

Yes, and sometimes preferable for accessing the latest 8.4 LTS releases before Ubuntu updates their packages. Download the mysql-apt-config.deb package from dev.mysql.com and install it to add Oracle's repository. However, Ubuntu's packages receive security patches through Canonical's team and integrate better with system tooling. For most Nepal-based client projects, I stick with Ubuntu repositories for simpler maintenance unless a specific MySQL feature requires the upstream version.

Share this article

Quick Contact Options
Choose how you want to connect me: