MariaDB
Install and configure MariaDB on Linux VPS, secure setup, user management, performance tuning and backup
MariaDB is an open-source relational database forked from MySQL, providing drop-in compatibility with MySQL syntax and tools. It's the default database server on Debian/Ubuntu and offers excellent performance for web applications, CMS platforms, and enterprise systems.
Installation
Ubuntu/Debian (Latest LTS - 10.11)
Use the official MariaDB Foundation repository for the latest stable version:
curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash
apt update
apt install mariadb-server -yStart and enable:
systemctl start mariadb
systemctl enable mariadbCentOS/AlmaLinux/Rocky
dnf install mariadb-server -y
systemctl start mariadb
systemctl enable mariadbVerify Installation
mariadb --version
mysql -u root -e "SELECT VERSION();"Secure Installation
Run the security wizard to harden your instance:
mysql_secure_installationThis removes:
- Anonymous user accounts
- Root remote login capability
- Test database
- Optionally disables password less authentication
Recommended answers:
Enter current password for root (press Enter): [ENTER]
Switch to unix_socket authentication? [Y/n] Y
Change the root password? [Y/n] n
Remove anonymous users? [Y/n] Y
Disable root login remotely? [Y/n] Y
Remove test database? [Y/n] Y
Reload privilege tables? [Y/n] YUser Management
Create Database and User
mysql -u root -pInside mysql prompt:
-- Create database
CREATE DATABASE wordpress;
-- Create local user (localhost only, most secure)
CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'secure_password_123';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'localhost';
-- Create remote user (from specific IP)
CREATE USER 'wordpress'@'192.168.1.100' IDENTIFIED BY 'secure_password_456';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'192.168.1.100';
-- Apply changes
FLUSH PRIVILEGES;
-- Verify
SHOW GRANTS FOR 'wordpress'@'localhost';
EXIT;Always use localhost connections when possible. Only allow remote connections from specific IPs that require them.
Grant Specific Permissions
-- Read-only user
CREATE USER 'reader'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT ON wordpress.* TO 'reader'@'localhost';
FLUSH PRIVILEGES;
-- User with specific tables
GRANT SELECT, INSERT, UPDATE ON wordpress.users TO 'wordpress'@'localhost';
FLUSH PRIVILEGES;Delete User
DROP USER 'olduser'@'localhost';
FLUSH PRIVILEGES;Configuration
Main Configuration File
Edit /etc/mysql/mariadb.conf.d/50-server.cnf:
nano /etc/mysql/mariadb.conf.d/50-server.cnfKey parameters:
# Network
bind-address = 127.0.0.1 # localhost only (secure)
bind-address = 0.0.0.0 # listen on all interfaces
# Connections
max_connections = 200 # adjust based on workload
# Memory (critical for performance)
# Set to 50-70% of system RAM
innodb_buffer_pool_size = 2G # main memory cache (8GB RAM = 6GB here)
innodb_log_file_size = 512M
# Query cache (disable on MariaDB 10.5+)
# query_cache_type = OFF
# Logging
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2 # log queries slower than 2 seconds
# InnoDB
innodb_file_per_table = 1
innodb_flush_log_at_trx_commit = 2 # balance between safety and performanceRestart to apply changes:
systemctl restart mariadbVerify Configuration
mysql -u root -p-- Check current settings
SHOW VARIABLES LIKE 'max_connections';
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'slow_query_log';
-- Monitor live connections
SHOW PROCESSLIST;
SHOW STATUS LIKE 'Threads%';Essential Commands
Database Operations
-- List databases
SHOW DATABASES;
-- Select database
USE wordpress;
-- Create database
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- List tables
SHOW TABLES;
-- Describe table structure
DESCRIBE users;
-- Drop database
DROP DATABASE myapp;User Operations
-- List all users
SELECT user, host FROM mysql.user;
-- Show user grants
SHOW GRANTS FOR 'wordpress'@'localhost';
-- Change password
ALTER USER 'wordpress'@'localhost' IDENTIFIED BY 'new_password';
FLUSH PRIVILEGES;Server Status
-- Check server uptime and connections
SHOW STATUS LIKE 'Uptime';
SHOW STATUS LIKE 'Threads%';
SHOW STATUS LIKE 'Questions';
-- Show active queries
SHOW PROCESSLIST;Backup
Backup Single Database
mysqldump -u wordpress -p wordpress > wordpress_$(date +%Y%m%d).sql
# Compressed backup
mysqldump -u wordpress -p wordpress | gzip > wordpress_$(date +%Y%m%d).sql.gzBackup All Databases
mysqldump -u root -p --all-databases | gzip > all_databases_$(date +%Y%m%d).sql.gzBackup with Locks (Minimal Downtime)
mysqldump -u root -p --single-transaction --lock-tables=false wordpress > backup.sqlRestore Database
# From SQL file
mysql -u root -p wordpress < wordpress_20250329.sql
# From compressed file
gunzip < wordpress_20250329.sql.gz | mysql -u root -p wordpressAutomated Backup Script
#!/bin/bash
BACKUP_DIR="/backups/mysql"
DATE=$(date +%Y%m%d)
MYSQL_USER="root"
MYSQL_PASS="your_password"
mkdir -p $BACKUP_DIR
# Backup all databases
mysqldump -u $MYSQL_USER -p$MYSQL_PASS \
--single-transaction \
--lock-tables=false \
--all-databases | \
gzip > $BACKUP_DIR/all_databases_$DATE.sql.gz
# Keep only last 30 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
echo "Backup completed: $BACKUP_DIR/all_databases_$DATE.sql.gz"Add to crontab for daily backups at 2 AM:
0 2 * * * /usr/local/bin/mysql-backup.shHot Backup with Mariabackup
For large databases with minimal downtime:
apt install mariadb-backup -y
# Create backup
mariabackup --backup --target-dir=/backups/mysql-full --user=root --password=
# Prepare backup
mariabackup --prepare --target-dir=/backups/mysql-full
# Restore (stop MariaDB first)
systemctl stop mariadb
mv /var/lib/mysql /var/lib/mysql.old
mariabackup --copy-back --target-dir=/backups/mysql-full
chown -R mysql:mysql /var/lib/mysql
systemctl start mariadbPerformance Tuning
Check Slow Queries
tail -f /var/log/mysql/slow.logAnalyze Query Performance
EXPLAIN SELECT * FROM users WHERE email='user@example.com';Look for table scans without index usage.
Add Index to Improve Performance
-- Check if index exists
SHOW INDEX FROM users;
-- Add index
CREATE INDEX idx_email ON users(email);
ALTER TABLE users ADD INDEX idx_email (email);Monitor Memory Usage
SHOW STATUS WHERE variable_name IN (
'Innodb_buffer_pool_bytes_data',
'Innodb_buffer_pool_bytes_dirty'
);Remote Connection Security
Enable Remote Access (Carefully)
Do NOT expose port 3306 to the internet. Always use SSH tunnel or VPN for remote access.
For specific IP only:
nano /etc/mysql/mariadb.conf.d/50-server.cnf
# bind-address = 192.168.1.50 # specific IPRestart:
systemctl restart mariadbSSH Tunnel for Remote Access
Connect from remote machine:
ssh -L 3306:localhost:3306 user@vps.example.com -NThen connect locally:
mysql -h 127.0.0.1 -u wordpress -p wordpressSSL/TLS for Encrypted Connections
-- Create user with SSL required
CREATE USER 'secure_user'@'192.168.1.100' IDENTIFIED BY 'password'
REQUIRE SSL;
FLUSH PRIVILEGES;Generate certificates:
mysql_ssl_rsa_setup --datadir=/var/lib/mysql
chown -R mysql:mysql /var/lib/mysql/
systemctl restart mariadbMonitoring
Useful Monitoring Queries
-- Database sizes
SELECT
table_schema AS database_name,
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS size_mb
FROM information_schema.tables
GROUP BY table_schema
ORDER BY size_mb DESC;
-- Top 10 largest tables
SELECT
table_schema,
table_name,
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb
FROM information_schema.tables
ORDER BY (data_length + index_length) DESC
LIMIT 10;
-- Current connections by user
SELECT user, COUNT(*) FROM information_schema.processlist GROUP BY user;Monitor with mytop (optional)
apt install mytop
mytop -u root -pMaintenance
Repair Tables (if corrupted)
mysqlcheck -u root -p --auto-repair --optimize wordpressOptimize All Databases
mysqlcheck -u root -p --optimize --all-databasesCheck Table Status
CHECK TABLE users;
REPAIR TABLE users;
OPTIMIZE TABLE users;