MySQL y MariaDB son los servidores de bases de datos relacionales más usados en aplicaciones web: WordPress, Laravel, Magento o Nextcloud funcionan con cualquiera de los dos. En este tutorial instalarás uno de ellos en Ubuntu 24.04 desde los repositorios oficiales de Ubuntu, lo asegurarás, crearás una base de datos con su propio usuario, ajustarás los parámetros básicos de rendimiento y programarás copias de seguridad diarias.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
- Un usuario no root con privilegios
sudo. - Al menos 1 GB de RAM; 2 GB o más si la base de datos va a tener carga real.
¿MySQL o MariaDB?
MariaDB nació como una bifurcación de MySQL y ambos son compatibles a nivel de cliente y de SQL básico, pero sus versiones actuales ya divergen en funciones avanzadas. En Ubuntu 24.04 los repositorios incluyen:
| MySQL | MariaDB | |
|---|---|---|
| Paquete | mysql-server | mariadb-server |
| Versión en Ubuntu 24.04 | 8.0 | 10.11 LTS |
| Cliente | mysql | mariadb (también mysql) |
| Configuración del servidor | /etc/mysql/mysql.conf.d/ | /etc/mysql/mariadb.conf.d/ |
| Servicio systemd | mysql | mariadb |
Si tu aplicación indica uno en concreto, instala ese. Si no, cualquiera sirve. No instales los dos en el mismo servidor: usan el mismo puerto y los mismos directorios.
Paso 1: Instalar el servidor
Actualiza el índice de paquetes:
sudo apt update
Instala MySQL:
sudo apt install mysql-server
O instala MariaDB:
sudo apt install mariadb-server
El servicio se arranca y se habilita automáticamente. Compruébalo (usa mariadb en lugar de mysql si instalaste MariaDB):
sudo systemctl status mysql
● mysql.service - MySQL Community Server
Loaded: loaded (/usr/lib/systemd/system/mysql.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-09-25 10:02:11 UTC; 15s ago
Pulsa q para salir. Comprueba la versión instalada:
mysql --version
mysql Ver 8.0.43-0ubuntu0.24.04.1 for Linux on x86_64 ((Ubuntu))
Paso 2: Asegurar la instalación
Ambos servidores incluyen un script que elimina usuarios anónimos, la base de datos de prueba y el acceso remoto de root. En Ubuntu, el usuario root de la base de datos se autentica por socket: solo el usuario root del sistema (o con sudo) puede entrar como root en la base de datos, sin contraseña. Es más seguro que una contraseña y conviene mantenerlo así.
En MySQL, ejecuta:
sudo mysql_secure_installation
Responde a las preguntas:
- VALIDATE PASSWORD component: si respondes
y, MySQL rechazará contraseñas débiles para los nuevos usuarios. Elige el nivel1(MEDIUM) o2(STRONG). - El script indica que se omite la contraseña de root porque usa
auth_socket. Es lo esperado. - Remove anonymous users, Disallow root login remotely, Remove test database y Reload privilege tables: responde
ya todas.
En MariaDB, el script se llama distinto:
sudo mariadb-secure-installation
Pulsa Enter cuando pida la contraseña actual de root (no tiene). Responde n a Switch to unix_socket authentication (ya la usa) y a Change the root password, y y al resto de preguntas.
Verifica que puedes entrar como root con sudo:
sudo mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
...
mysql>
Escribe exit para salir. Sin sudo, mysql -u root debe fallar con ERROR 1698 (28000): Access denied, lo que confirma que root solo es accesible localmente con privilegios del sistema.
Paso 3: Crear una base de datos y un usuario
Cada aplicación debe tener su propia base de datos y un usuario con permisos solo sobre ella, nunca usar root. Entra en la consola:
sudo mysql
Crea la base de datos con utf8mb4, la codificación que admite todos los caracteres Unicode, incluidos los emojis:
CREATE DATABASE app_db CHARACTER SET utf8mb4;
Crea el usuario. Sustituye your_strong_password por una contraseña larga y aleatoria (puedes generarla con openssl rand -base64 24):
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;
exit
'app_user'@'localhost' significa que este usuario solo puede conectarse desde el propio servidor, que es lo correcto cuando la aplicación se ejecuta en la misma máquina. Comprueba que el usuario funciona:
mysql -u app_user -p app_db -e "SELECT CURRENT_USER(), DATABASE();"
+--------------------+------------+
| CURRENT_USER() | DATABASE() |
+--------------------+------------+
| app_user@localhost | app_db |
+--------------------+------------+
Paso 4: Ajustar la configuración
En lugar de modificar los archivos del paquete, crea uno propio con un nombre que se lea al final para que sus valores prevalezcan. Para MySQL:
sudo nano /etc/mysql/mysql.conf.d/99-custom.cnf
Para MariaDB, crea el mismo archivo en /etc/mysql/mariadb.conf.d/99-custom.cnf. El contenido es igual para ambos:
[mysqld]
# Memoria para caché de datos e índices de InnoDB.
# En un servidor dedicado a la base de datos, entre el 50 % y el 70 % de la RAM.
# En un servidor compartido con la web, alrededor del 25 %.
innodb_buffer_pool_size = 1G
# Conexiones simultáneas máximas (el valor por defecto es 151)
max_connections = 200
# Registrar consultas que tardan más de 1 segundo
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 1
# Codificación por defecto para bases de datos nuevas
character-set-server = utf8mb4
Los valores de ejemplo son para un servidor de 4 GB compartido con la aplicación; adáptalos a tu RAM. Un innodb_buffer_pool_size demasiado alto provoca que el sistema se quede sin memoria y el kernel mate el proceso.
Reinicia el servicio para aplicar los cambios (mariadb si usas MariaDB):
sudo systemctl restart mysql
Verifica que se han aplicado:
sudo mysql -e "SHOW VARIABLES WHERE Variable_name IN ('innodb_buffer_pool_size','max_connections','slow_query_log');"
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| innodb_buffer_pool_size | 1073741824 |
| max_connections | 200 |
| slow_query_log | ON |
+-------------------------+------------+
Si el servicio no arranca, revisa el error con sudo journalctl -u mysql -n 30 (o -u mariadb); normalmente es un nombre de variable mal escrito.
Paso 5: Permitir conexiones remotas (opcional)
Por defecto el servidor solo escucha en 127.0.0.1, lo que impide cualquier conexión desde fuera. Si tu aplicación está en la misma máquina, sáltate este paso. Si está en otro servidor, abre el acceso solo para esa IP.
Añade la dirección de escucha en tu archivo 99-custom.cnf, dentro de [mysqld]:
bind-address = 0.0.0.0
Si el servidor tiene una red privada con la máquina de la aplicación, usa su IP privada en lugar de 0.0.0.0. Reinicia el servicio y crea un usuario limitado a la IP de la aplicación, representada aquí como 203.0.113.10:
sudo systemctl restart mysql
sudo mysql
CREATE USER 'app_user'@'203.0.113.10' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'203.0.113.10';
FLUSH PRIVILEGES;
exit
Permite el puerto 3306 en el firewall solo para esa IP:
sudo ufw allow from 203.0.113.10 to any port 3306 proto tcp
Nunca abras el puerto 3306 a todo Internet: los bots prueban contraseñas contra él continuamente. Comprueba que el servidor escucha en la nueva dirección:
sudo ss -tlnp | grep 3306
LISTEN 0 151 0.0.0.0:3306 0.0.0.0:* users:(("mysqld",pid=4121,fd=23))
Desde el servidor de la aplicación, prueba la conexión con mysql -h your_server_ip -u app_user -p app_db.
NotaMySQL 8.0 genera un certificado autofirmado al instalarse y cifra las conexiones remotas con TLS si el cliente lo admite. En MariaDB 10.11 el cifrado no viene activado por defecto; si la conexión va por Internet y no por una red privada, configura TLS o usa un túnel SSH o WireGuard.
Paso 6: Programar copias de seguridad
mysqldump (en MariaDB también disponible como mariadb-dump) genera un volcado SQL que puedes restaurar en cualquier servidor. Con --single-transaction obtiene una copia coherente de las tablas InnoDB sin bloquearlas.
Crea el directorio de copias, accesible solo para root:
sudo install -d -m 700 /var/backups/mysql
Crea el script:
sudo nano /usr/local/bin/mysql-backup.sh
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/var/backups/mysql"
RETENTION_DAYS=7
STAMP="$(date +%F_%H%M)"
# Volcar cada base de datos de usuario en su propio archivo comprimido
mysql -N -e "SHOW DATABASES" | grep -Ev '^(information_schema|performance_schema|mysql|sys)$' |
while read -r db; do
mysqldump --single-transaction --routines --triggers --events "$db" |
gzip > "${BACKUP_DIR}/${db}_${STAMP}.sql.gz"
done
# Borrar copias más antiguas que la retención
find "$BACKUP_DIR" -name '*.sql.gz' -mtime +"$RETENTION_DAYS" -delete
El script se ejecuta como root, que accede a la base de datos por socket, así que no necesita contraseñas en ningún archivo. Hazlo ejecutable y pruébalo:
sudo chmod 700 /usr/local/bin/mysql-backup.sh
sudo /usr/local/bin/mysql-backup.sh
sudo ls -lh /var/backups/mysql
-rw-r--r-- 1 root root 1.2K Sep 25 10:40 app_db_2026-09-25_1040.sql.gz
Prográmalo a diario a las 3:30 con cron:
echo '30 3 * * * root /usr/local/bin/mysql-backup.sh' | sudo tee /etc/cron.d/mysql-backup
Para restaurar una copia en una base de datos existente:
gunzip < /var/backups/mysql/app_db_2026-09-25_1040.sql.gz | sudo mysql app_db
Importanteuna copia guardada en el mismo disco que la base de datos no te protege si pierdes el servidor. Copia
/var/backups/mysqla otro sistema, por ejemplo conrsyncorclonea un almacenamiento de objetos, y prueba la restauración de vez en cuando.
Solución de problemas
ERROR 1698 (28000): Access denied for user 'root'@'localhost'. Estás intentando entrar como root sin sudo. Usa sudo mysql. Para las aplicaciones, crea un usuario propio como en el paso 3.
ERROR 1045 (28000): Access denied for user 'app_user'@'...'. La contraseña es incorrecta o el usuario no existe para ese host. Un usuario 'app_user'@'localhost' no sirve para conexiones remotas. Lista los usuarios con sudo mysql -e "SELECT user, host FROM mysql.user;".
ERROR 2003: Can't connect to MySQL server. El servicio no está en marcha, escucha solo en 127.0.0.1 o el firewall bloquea el puerto. Revisa systemctl status, la salida de ss -tlnp y las reglas con sudo ufw status.
El servicio se reinicia solo o lo mata el sistema. Busca Out of memory en sudo journalctl -k | grep -i oom. Reduce innodb_buffer_pool_size o añade RAM.
Consultas lentas. Revisa /var/log/mysql/mysql-slow.log y analiza las consultas que aparecen con EXPLAIN. Casi siempre falta un índice.
Conclusión
Tienes MySQL o MariaDB instalado y asegurado, con root accesible solo por socket, un usuario dedicado para tu aplicación, parámetros de memoria adaptados al servidor, registro de consultas lentas y copias de seguridad diarias con rotación.
Como siguientes pasos puedes:
- Copiar las copias de seguridad fuera del servidor y documentar el procedimiento de restauración.
- Usar
mysqldumpslowsobre el log de consultas lentas para priorizar qué optimizar. - Configurar una réplica para alta disponibilidad o para descargar las consultas de lectura.
