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:

MySQLMariaDB
Paquetemysql-servermariadb-server
Versión en Ubuntu 24.048.010.11 LTS
Clientemysqlmariadb (también mysql)
Configuración del servidor/etc/mysql/mysql.conf.d//etc/mysql/mariadb.conf.d/
Servicio systemdmysqlmariadb

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 nivel 1 (MEDIUM) o 2 (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 y a 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.

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

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 mysqldumpslow sobre el log de consultas lentas para priorizar qué optimizar.
  • Configurar una réplica para alta disponibilidad o para descargar las consultas de lectura.