Set up MariaDB 11.6 as a high-performance MySQL alternative with InnoDB optimization, SSL encryption, automated backups, and comprehensive security hardening for production environments.
Prerequisites
- Root or sudo access
- At least 2GB RAM (4GB recommended)
- 10GB free disk space
- Basic command line knowledge
What this solves
MariaDB 11.6 provides a robust, open-source alternative to MySQL with enhanced performance features, better security defaults, and improved scalability. This tutorial covers installing MariaDB 11.6 from official repositories, configuring InnoDB storage engine optimization, implementing SSL/TLS encryption, setting up automated backups, and hardening security configurations for production deployment.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest security updates and dependencies.
sudo apt update && sudo apt upgrade -yAdd MariaDB official repository
Add the official MariaDB repository to get the latest 11.6 version with security updates and performance improvements.
sudo apt install -y software-properties-common dirmngr apt-transport-https
curl -o /tmp/mariadb_repo_setup https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
echo "2c3b4f28d37cfef9d69e5e0ac62df8a8ebc88e6e mariadb_repo_setup" | sha1sum -c -
sudo bash /tmp/mariadb_repo_setup --mariadb-server-version="mariadb-11.6"
sudo apt updateInstall MariaDB 11.6 server and client
Install the complete MariaDB server package with client tools and development libraries for application connectivity.
sudo apt install -y mariadb-server mariadb-client mariadb-backupEnable and start MariaDB service
Enable MariaDB to start automatically on boot and start the service immediately for configuration.
sudo systemctl enable --now mariadb
sudo systemctl status mariadbRun initial security configuration
Execute the mysql_secure_installation script to remove insecure defaults, set root password, and configure basic security settings.
sudo mysql_secure_installationWhen prompted, choose these security settings:
- Set root password: Yes (use a strong password)
- Remove anonymous users: Yes
- Disallow root login remotely: Yes
- Remove test database: Yes
- Reload privilege tables: Yes
Performance optimization configuration
Create optimized MariaDB configuration
Configure InnoDB storage engine settings, query cache, and connection limits for optimal performance based on available system memory.
[mysqld]
Basic settings
bind-address = 127.0.0.1
port = 3306
max_connections = 200
max_connect_errors = 1000000
InnoDB settings for performance
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_open_files = 400
innodb_io_capacity = 400
innodb_io_capacity_max = 2000
Query cache settings
query_cache_type = 1
query_cache_size = 128M
query_cache_limit = 2M
Temporary tables
tmp_table_size = 64M
max_heap_table_size = 64M
Logging
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mariadb-slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
Security
local_infile = 0
skip_show_databaseAdjust buffer pool size based on system memory
Set innodb_buffer_pool_size to 70-80% of available RAM for dedicated database servers. Check your system memory first.
free -h
For 4GB RAM system: innodb_buffer_pool_size = 3G
For 8GB RAM system: innodb_buffer_pool_size = 6G
For 16GB RAM system: innodb_buffer_pool_size = 12G
Create log directory with correct permissions
Create the slow query log directory and set appropriate ownership for the mysql user to write log files.
sudo mkdir -p /var/log/mysql
sudo chown mysql:mysql /var/log/mysql
sudo chmod 750 /var/log/mysqlRestart MariaDB with new configuration
Restart the service to apply performance optimizations and verify the configuration is valid.
sudo systemctl restart mariadb
sudo systemctl status mariadbSSL/TLS encryption setup
Generate SSL certificates for MariaDB
Create self-signed SSL certificates for encrypted client connections and replication security.
sudo mkdir -p /etc/mysql/ssl
sudo openssl genrsa 2048 > /etc/mysql/ssl/ca-key.pem
sudo openssl req -new -x509 -nodes -days 365000 -key /etc/mysql/ssl/ca-key.pem -out /etc/mysql/ssl/ca-cert.pem -subj "/C=US/ST=State/L=City/O=Organization/CN=MariaDB-CA"
sudo openssl req -newkey rsa:2048 -days 365000 -nodes -keyout /etc/mysql/ssl/server-key.pem -out /etc/mysql/ssl/server-req.pem -subj "/C=US/ST=State/L=City/O=Organization/CN=MariaDB-Server"
sudo openssl x509 -req -in /etc/mysql/ssl/server-req.pem -days 365000 -CA /etc/mysql/ssl/ca-cert.pem -CAkey /etc/mysql/ssl/ca-key.pem -set_serial 01 -out /etc/mysql/ssl/server-cert.pemSet SSL certificate permissions
Configure secure file permissions for SSL certificates to prevent unauthorized access while allowing MariaDB to read them.
sudo chown -R mysql:mysql /etc/mysql/ssl
sudo chmod 600 /etc/mysql/ssl/*-key.pem
sudo chmod 644 /etc/mysql/ssl/*-cert.pem
sudo chmod 644 /etc/mysql/ssl/ca-cert.pemConfigure SSL in MariaDB
Enable SSL encryption for client connections and configure certificate paths in the MariaDB configuration.
[mysqld]
SSL Configuration
ssl-ca = /etc/mysql/ssl/ca-cert.pem
ssl-cert = /etc/mysql/ssl/server-cert.pem
ssl-key = /etc/mysql/ssl/server-key.pem
require_secure_transport = ON
[client]
ssl-ca = /etc/mysql/ssl/ca-cert.pemRestart MariaDB and verify SSL
Restart the service to enable SSL encryption and verify that SSL is working correctly.
sudo systemctl restart mariadb
sudo mysql -u root -p -e "SHOW VARIABLES LIKE 'have_ssl';"
sudo mysql -u root -p -e "SHOW VARIABLES LIKE 'ssl_%';"Database and user management
Create application database
Create a dedicated database for your application with proper character set and collation for international support.
sudo mysql -u root -pCREATE DATABASE myapp_production CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
SHOW DATABASES;Create application user with limited privileges
Create a dedicated database user with minimum required privileges following the principle of least privilege for security.
CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'SecureP@ssw0rd123!';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON myapp_production.* TO 'myapp_user'@'localhost';
FLUSH PRIVILEGES;
SHOW GRANTS FOR 'myapp_user'@'localhost';
EXIT;Test user connection and permissions
Verify that the new user can connect and access only the intended database with the granted privileges.
mysql -u myapp_user -p -h localhost myapp_production
Test in MariaDB console:
USE myapp_production;
CREATE TABLE test_table (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO test_table VALUES (1, 'test');
SELECT * FROM test_table;
DROP TABLE test_table;
Automated backup configuration
Create backup script
Create an automated backup script using mariadb-dump for consistent database backups with compression and rotation.
#!/bin/bash
MariaDB backup configuration
DB_USER="root"
DB_HOST="localhost"
BACKUP_DIR="/var/backups/mariadb"
DATE=$(date +"%Y%m%d_%H%M%S")
RETENTION_DAYS=7
Create backup directory
mkdir -p $BACKUP_DIR
Database list (exclude system databases for application backups)
DATABASES="myapp_production"
Create backup
for DB in $DATABASES; do
echo "Backing up database: $DB"
mariadb-dump --user=$DB_USER --password --host=$DB_HOST \
--single-transaction --routines --triggers \
$DB | gzip > $BACKUP_DIR/${DB}_${DATE}.sql.gz
if [ $? -eq 0 ]; then
echo "Backup completed: ${DB}_${DATE}.sql.gz"
else
echo "Backup failed for database: $DB"
exit 1
fi
done
Remove old backups
find $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
echo "Backup process completed at $(date)"Set backup script permissions
Make the backup script executable and secure it with appropriate permissions to prevent unauthorized access.
sudo chmod 750 /usr/local/bin/mariadb-backup.sh
sudo chown root:mysql /usr/local/bin/mariadb-backup.shCreate backup directory
Create the backup directory with secure permissions and ensure adequate disk space for backup retention.
sudo mkdir -p /var/backups/mariadb
sudo chown mysql:mysql /var/backups/mariadb
sudo chmod 750 /var/backups/mariadbSchedule automated backups
Configure daily automated backups using cron to run during low-traffic periods for minimal performance impact.
sudo crontab -e# Daily MariaDB backup at 2:30 AM
30 2 * /usr/local/bin/mariadb-backup.sh >> /var/log/mariadb-backup.log 2>&1Test backup script
Run the backup script manually to verify it works correctly and check backup file creation.
sudo /usr/local/bin/mariadb-backup.sh
sudo ls -la /var/backups/mariadb/
sudo zcat /var/backups/mariadb/myapp_production_*.sql.gz | head -20Firewall and access control
Configure firewall rules
Set up firewall rules to allow MariaDB access only from trusted sources and block unauthorized connection attempts.
# Allow MySQL/MariaDB from localhost only
sudo ufw allow from 127.0.0.1 to any port 3306
For remote access from specific IP:
sudo ufw allow from 203.0.113.10 to any port 3306
sudo ufw statusConfigure connection limits and timeouts
Add additional security configurations to prevent connection abuse and improve security hardening.
[mysqld]
Connection security
max_user_connections = 50
max_connections = 200
connect_timeout = 10
wait_timeout = 600
interactive_timeout = 600
Disable dangerous functions
local_infile = 0
Enable logging for security monitoring
log_warnings = 2
general_log = 0
general_log_file = /var/log/mysql/general.logApply final security configuration
Restart MariaDB to apply all security configurations and verify the service is running with new settings.
sudo systemctl restart mariadb
sudo systemctl status mariadbVerify your setup
Run these commands to verify your MariaDB installation, performance configuration, and security settings are working correctly.
# Check MariaDB version and status
sudo systemctl status mariadb
mariadb --version
Verify SSL configuration
sudo mysql -u root -p -e "SHOW VARIABLES LIKE 'have_ssl';"
sudo mysql -u root -p -e "SHOW VARIABLES LIKE 'ssl_%';"
Check InnoDB configuration
sudo mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
sudo mysql -u root -p -e "SHOW ENGINE INNODB STATUS\G" | head -20
Verify user privileges
sudo mysql -u root -p -e "SELECT User, Host FROM mysql.user;"
Test backup files
sudo ls -la /var/backups/mariadb/
Check log files
sudo tail -20 /var/log/mysql/mariadb-slow.logYou can also test application connectivity and monitor performance with these commands. If you linked this setup with applications, verify they can connect using the SSL-enabled connection string.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| MariaDB won't start after config changes | Configuration syntax error | sudo mysqld --help --verbose to check config |
| SSL connection fails | Certificate permissions or paths wrong | Check chown mysql:mysql /etc/mysql/ssl/* and file paths |
| Application can't connect | User permissions or firewall blocking | Verify SHOW GRANTS FOR 'user'@'host' and firewall rules |
| Poor query performance | InnoDB buffer pool too small | Adjust innodb_buffer_pool_size to 70-80% of RAM |
| Backup script fails | Directory permissions or disk space | Check df -h and chmod 750 /var/backups/mariadb |
| Connection refused from remote hosts | bind-address restricting connections | Change bind-address = 0.0.0.0 and update firewall rules |
Next steps
- Configure advanced firewall rules for database security
- Set up MariaDB master-slave replication for high availability
- Configure MariaDB Galera cluster for distributed database setup
- Advanced MariaDB performance tuning and query optimization
- Monitor MariaDB performance with Prometheus and Grafana dashboards
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Usage message
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " --root-password PASSWORD Set MariaDB root password (default: prompts)"
echo " --buffer-pool-size SIZE InnoDB buffer pool size (default: auto-detect)"
echo " -h, --help Show this help message"
exit 1
}
# Parse arguments
MYSQL_ROOT_PASSWORD=""
BUFFER_POOL_SIZE=""
while [[ $# -gt 0 ]]; do
case $1 in
--root-password)
MYSQL_ROOT_PASSWORD="$2"
shift 2
;;
--buffer-pool-size)
BUFFER_POOL_SIZE="$2"
shift 2
;;
-h|--help)
usage
;;
*)
log_error "Unknown option: $1"
usage
;;
esac
done
# Cleanup function for rollback
cleanup() {
log_error "Installation failed. Cleaning up..."
systemctl stop mariadb 2>/dev/null || true
if [[ "$PKG_MGR" == "apt" ]]; then
apt remove -y mariadb-server mariadb-client mariadb-backup 2>/dev/null || true
else
$PKG_INSTALL remove -y MariaDB-server MariaDB-client MariaDB-backup 2>/dev/null || true
fi
rm -f /tmp/mariadb_repo_setup
}
trap cleanup ERR
# Check prerequisites
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root or with sudo"
exit 1
fi
# Auto-detect distribution
if [[ ! -f /etc/os-release ]]; then
log_error "/etc/os-release not found. Cannot determine distribution."
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
MYSQL_CONFIG_DIR="/etc/mysql/mariadb.conf.d"
MYSQL_LOG_DIR="/var/log/mysql"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
MYSQL_CONFIG_DIR="/etc/my.cnf.d"
MYSQL_LOG_DIR="/var/log/mariadb"
;;
fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
MYSQL_CONFIG_DIR="/etc/my.cnf.d"
MYSQL_LOG_DIR="/var/log/mariadb"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
MYSQL_CONFIG_DIR="/etc/my.cnf.d"
MYSQL_LOG_DIR="/var/log/mariadb"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
log_info "Detected distribution: $ID"
# Auto-detect optimal buffer pool size
if [[ -z "$BUFFER_POOL_SIZE" ]]; then
TOTAL_MEM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
TOTAL_MEM_GB=$((TOTAL_MEM_KB / 1024 / 1024))
if [[ $TOTAL_MEM_GB -ge 16 ]]; then
BUFFER_POOL_SIZE="12G"
elif [[ $TOTAL_MEM_GB -ge 8 ]]; then
BUFFER_POOL_SIZE="6G"
elif [[ $TOTAL_MEM_GB -ge 4 ]]; then
BUFFER_POOL_SIZE="3G"
else
BUFFER_POOL_SIZE="1G"
fi
log_info "Auto-detected buffer pool size: $BUFFER_POOL_SIZE (Total RAM: ${TOTAL_MEM_GB}GB)"
fi
echo "[1/10] Updating system packages..."
$PKG_UPDATE
echo "[2/10] Installing prerequisites..."
if [[ "$PKG_MGR" == "apt" ]]; then
$PKG_INSTALL software-properties-common dirmngr apt-transport-https curl
else
$PKG_INSTALL curl
fi
echo "[3/10] Adding MariaDB official repository..."
curl -o /tmp/mariadb_repo_setup https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
if ! echo "2c3b4f28d37cfef9d69e5e0ac62df8a8ebc88e6e /tmp/mariadb_repo_setup" | sha1sum -c -; then
log_error "MariaDB repository setup script checksum verification failed"
exit 1
fi
chmod 755 /tmp/mariadb_repo_setup
bash /tmp/mariadb_repo_setup --mariadb-server-version="mariadb-11.6"
echo "[4/10] Updating package lists..."
if [[ "$PKG_MGR" == "apt" ]]; then
apt update
else
$PKG_UPDATE
fi
echo "[5/10] Installing MariaDB 11.6..."
if [[ "$PKG_MGR" == "apt" ]]; then
$PKG_INSTALL mariadb-server mariadb-client mariadb-backup
else
$PKG_INSTALL MariaDB-server MariaDB-client MariaDB-backup
fi
echo "[6/10] Enabling and starting MariaDB service..."
systemctl enable mariadb
systemctl start mariadb
# Wait for MariaDB to be ready
sleep 3
systemctl is-active --quiet mariadb || {
log_error "MariaDB service failed to start"
exit 1
}
echo "[7/10] Creating performance configuration..."
mkdir -p "$MYSQL_CONFIG_DIR"
cat > "$MYSQL_CONFIG_DIR/99-performance.cnf" << EOF
[mysqld]
# Basic settings
bind-address = 127.0.0.1
port = 3306
max_connections = 200
max_connect_errors = 1000000
# InnoDB settings for performance
innodb_buffer_pool_size = $BUFFER_POOL_SIZE
innodb_log_file_size = 256M
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_open_files = 400
innodb_io_capacity = 400
innodb_io_capacity_max = 2000
# Query cache settings
query_cache_type = 1
query_cache_size = 128M
query_cache_limit = 2M
# Temporary tables
tmp_table_size = 64M
max_heap_table_size = 64M
# Logging
slow_query_log = 1
slow_query_log_file = $MYSQL_LOG_DIR/mariadb-slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
# Security
local_infile = 0
skip_show_database
EOF
chmod 644 "$MYSQL_CONFIG_DIR/99-performance.cnf"
echo "[8/10] Creating log directory..."
mkdir -p "$MYSQL_LOG_DIR"
chown mysql:mysql "$MYSQL_LOG_DIR"
chmod 750 "$MYSQL_LOG_DIR"
echo "[9/10] Running security configuration..."
systemctl restart mariadb
if [[ -z "$MYSQL_ROOT_PASSWORD" ]]; then
log_warn "Running interactive mysql_secure_installation..."
mysql_secure_installation
else
# Non-interactive security setup
mysql -u root << EOF
UPDATE mysql.user SET Password=PASSWORD('$MYSQL_ROOT_PASSWORD') WHERE User='root';
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
EOF
fi
echo "[10/10] Verifying installation..."
if systemctl is-active --quiet mariadb; then
log_info "✓ MariaDB service is running"
else
log_error "✗ MariaDB service is not running"
exit 1
fi
MARIADB_VERSION=$(mysql --version | grep -oP 'MariaDB \K[0-9]+\.[0-9]+\.[0-9]+')
if [[ "$MARIADB_VERSION" =~ ^11\.6\. ]]; then
log_info "✓ MariaDB version $MARIADB_VERSION is installed"
else
log_warn "! MariaDB version $MARIADB_VERSION (expected 11.6.x)"
fi
if [[ -f "$MYSQL_CONFIG_DIR/99-performance.cnf" ]]; then
log_info "✓ Performance configuration applied"
else
log_error "✗ Performance configuration missing"
fi
if [[ -d "$MYSQL_LOG_DIR" ]]; then
log_info "✓ Log directory created with correct permissions"
else
log_error "✗ Log directory missing"
fi
# Clean up temporary files
rm -f /tmp/mariadb_repo_setup
log_info "MariaDB 11.6 installation completed successfully!"
log_info "Configuration file: $MYSQL_CONFIG_DIR/99-performance.cnf"
log_info "Log directory: $MYSQL_LOG_DIR"
log_info "Buffer pool size: $BUFFER_POOL_SIZE"
log_warn "Please restart MariaDB to apply all configuration changes: systemctl restart mariadb"
Review the script before running. Execute with: bash install.sh