VPS

MySQL/MariaDB Optimization on VPS — Speed Up Your Database

Updated: October 13, 2026 · 12 min read · AsiaGB.com

MySQL MariaDB optimization on Linux VPS server

MySQL and MariaDB are the most widely used databases on VPS servers, but their default configurations are designed for low-memory machines — not modern cloud VPS environments. This guide walks you through the most impactful tuning steps to maximize database performance.

Why Is MySQL Slow

Understanding the root cause before tuning is critical. Most out-of-the-box MySQL installations suffer from these common issues:

ProblemRoot CauseImpact
innodb_buffer_pool_size too smallDefault is only 128MBConstant disk reads, very slow
max_connections set too highPre-allocates RAM per connectionRAM exhaustion, heavy swapping
Missing indexesNo EXPLAIN analysis doneFull table scans on every query
No slow query loggingNot enabled by defaultCan't identify bottleneck queries
Binary logging enabled unnecessarilySome distro defaultsWasted disk I/O

Tuning InnoDB Buffer Pool

The InnoDB buffer pool is the single most important MySQL tuning parameter. It caches table data and indexes in RAM, avoiding expensive disk reads. The larger it is, the better — up to the limit of available RAM.

Formula: Set innodb_buffer_pool_size to 50–70% of total RAM. Reserve the rest for the OS, PHP-FPM, and Nginx/Apache.

VPS RAMRecommended Value
2 GB1G
4 GB2G–2.5G
8 GB4G–5G
16 GB8G–10G

Check current buffer pool usage:

mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
mysql -u root -p -e "SHOW STATUS LIKE 'Innodb_buffer_pool_reads';"

Key my.cnf Settings

The main MySQL/MariaDB config file is at /etc/mysql/my.cnf or /etc/my.cnf depending on your distro. Here's a well-tuned starting configuration:

[mysqld]
# Buffer Pool — adjust based on available RAM
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 2

# Log File — larger = fewer checkpoints
innodb_log_file_size = 256M
innodb_log_buffer_size = 16M

# I/O Settings
innodb_flush_log_at_trx_commit = 2    # Reduce I/O (loses ~1s data on crash)
innodb_flush_method = O_DIRECT        # Avoid OS double buffering

# Connections
max_connections = 150                  # Reduce from default 151-200
thread_cache_size = 16

# Query Cache (MariaDB only — removed in MySQL 8)
# query_cache_type = 1
# query_cache_size = 64M
# query_cache_limit = 2M

# Tmp Tables — keep in RAM
tmp_table_size = 64M
max_heap_table_size = 64M

# Slow Query Log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

# Binary Log — disable if not using replication
# skip-log-bin

⚠️ MySQL 8.0 users: query_cache was completely removed. Do NOT add query_cache directives — MySQL will refuse to start.

After editing, restart MySQL:

sudo systemctl restart mysql
# or for MariaDB
sudo systemctl restart mariadb

Enabling Slow Query Log

The slow query log is your most powerful tool for identifying bottleneck queries. Enable it before you start tuning, then analyze after a few hours of production traffic.

# Check current status
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';

# Enable without restart
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

Analyze with mysqldumpslow:

# Show 10 slowest queries by total time
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# Show most frequently executed slow queries
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log

Index and Query Optimization

Good indexes can speed up queries by 100–1000x. Use EXPLAIN to verify your queries are using indexes efficiently.

-- Check query execution plan
EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 'pending';

-- Show existing indexes
SHOW INDEX FROM orders;

-- Add a composite index
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);

-- Remove an unused index
DROP INDEX old_index_name ON orders;

Tip: In EXPLAIN output, a type value of ALL means a full table scan. Add an appropriate index immediately.

Find unused indexes

-- MySQL 8 / MariaDB 10.6+
SELECT * FROM sys.schema_unused_indexes
WHERE object_schema NOT IN ('performance_schema','mysql','sys','information_schema');

Using MySQLTuner

MySQLTuner automatically analyzes your MySQL/MariaDB installation and recommends tuning values. Run it after at least 24 hours of production traffic for meaningful recommendations.

# Download
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl

# Run
perl mysqltuner.pl --user root --pass your_password

The output highlights:

MariaDB vs MySQL

For new VPS deployments, MariaDB is worth considering over MySQL:

FeatureMySQL 8.0MariaDB 10.11
Query OptimizerGoodBetter in many workloads
Query CacheRemovedAvailable (optional)
JSON SupportNative JSON typeDynamic columns + JSON
Storage EnginesInnoDB, MyISAMInnoDB, Aria, ColumnStore
Galera ClusterRequires pluginBuilt-in support
LicenseGPL/CommercialGPL (fully open)

Performance Monitoring

After tuning, monitor continuously to validate improvements:

# Real-time status
mysqladmin -u root -p status

# Active processes
SHOW PROCESSLIST;

# Key global status counters
SHOW GLOBAL STATUS LIKE 'Questions';
SHOW GLOBAL STATUS LIKE 'Slow_queries';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Aborted_connects';

Calculate Buffer Pool Hit Rate

-- Should be above 99%
SELECT
  (1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)) * 100
  AS buffer_pool_hit_rate
FROM (
  SELECT VARIABLE_VALUE AS Innodb_buffer_pool_reads
  FROM information_schema.GLOBAL_STATUS
  WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads'
) r,
(
  SELECT VARIABLE_VALUE AS Innodb_buffer_pool_read_requests
  FROM information_schema.GLOBAL_STATUS
  WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'
) rr;

Optimization Checklist

ItemAction
innodb_buffer_pool_sizeSet to 50-70% of total RAM
slow_query_logEnable with long_query_time = 2
max_connectionsReduce to match actual load
IndexesRun EXPLAIN on key queries
tmp_table_sizeSet to 64M to reduce disk tmp tables
MySQLTunerRun after 24h and apply recommendations
binary logDisable if not using replication
Buffer Pool Hit RateMust be above 99%

FAQ

Why is MySQL slow on my VPS?

MySQL defaults are designed for low-RAM machines, not modern VPS servers. The most impactful fix is increasing innodb_buffer_pool_size to 50-70% of available RAM, which caches data in memory instead of reading from disk constantly.

What should I set innodb_buffer_pool_size to?

Set it to 50-70% of total RAM. For a 4GB VPS, use innodb_buffer_pool_size = 2G. Leave enough RAM for the OS, PHP, and your web server to avoid excessive swapping.

What is the slow query log and how does it help?

The slow query log records queries that take longer than a threshold (long_query_time). By analyzing it with mysqldumpslow, you can identify queries that need better indexes or rewrites, directly targeting the root cause of slowness.

Should I use MariaDB instead of MySQL on my VPS?

MariaDB is a drop-in replacement for MySQL with a generally faster optimizer, built-in Galera Cluster support, and an active open-source community. For new VPS setups, MariaDB is a solid choice, especially on Ubuntu/Debian where it integrates well.

How do I check the InnoDB buffer pool hit rate?

Run SHOW GLOBAL STATUS for Innodb_buffer_pool_reads and Innodb_buffer_pool_read_requests, then calculate (1 - reads/read_requests) * 100. It should be above 99% for a well-tuned server.

Do I need to restart MySQL after editing my.cnf?

Most settings require a MySQL restart. Some can be changed live with SET GLOBAL, but those changes are lost on restart. Always update my.cnf first, then restart to make changes permanent.