Hosting Equipo Avantys 7 min

MySQL en VPS: Configuración y Optimización

Configura y optimiza MySQL/MariaDB en tu VPS. Instalación, seguridad, tunning de rendimiento, backups y solución de problemas comunes.

// Compartir

MySQL en VPS: Configuración y Optimización
MySQL en VPS - configuración y optimización

Una base de datos mal configurada es el cuello de botella más común en aplicaciones web. MySQL correctamente optimizado puede hacer que tu sitio vuele.

Esta guía te enseña a configurar y optimizar MySQL/MariaDB en tu VPS.

MySQL vs MariaDB

AspectoMySQLMariaDB
OrigenOracleFork de MySQL
Compatibilidad-100% con MySQL
RendimientoBuenoLigeramente mejor
LicenciaGPL + ComercialGPL
RecomendaciónEmpresas OracleMayoría de casos

Para la mayoría de VPS, MariaDB es la mejor opción. Los comandos son idénticos.

Instalación

Ubuntu/Debian

# MariaDB (recomendado)
sudo apt update
sudo apt install mariadb-server mariadb-client -y

# MySQL
sudo apt install mysql-server mysql-client -y

# Verificar
mysql --version
systemctl status mariadb  # o mysql

Asegurar instalación

sudo mysql_secure_installation

# Respuestas recomendadas:
# Set root password? → Y (establecer contraseña fuerte)
# Remove anonymous users? → Y
# Disallow root login remotely? → Y
# Remove test database? → Y
# Reload privilege tables? → Y

Configuración básica

Archivo de configuración

# MariaDB
/etc/mysql/mariadb.conf.d/50-server.cnf

# MySQL
/etc/mysql/mysql.conf.d/mysqld.cnf

Configuración inicial recomendada

[mysqld]
# Red
bind-address = 127.0.0.1
port = 3306

# Charset
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

# InnoDB (motor principal)
default-storage-engine = InnoDB
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# Conexiones
max_connections = 150
wait_timeout = 600
interactive_timeout = 600

# Caché de queries (solo MySQL 5.7, deshabilitado en 8.0)
# query_cache_type = 1
# query_cache_size = 64M

# Logs
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

# Temporal
tmp_table_size = 64M
max_heap_table_size = 64M
# Reiniciar para aplicar
sudo systemctl restart mariadb

Gestión de usuarios

Conectar como root

# Método 1: Socket (más seguro)
sudo mysql

# Método 2: Con contraseña
mysql -u root -p

Crear usuario y base de datos

-- Crear base de datos
CREATE DATABASE mi_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Crear usuario
CREATE USER 'mi_usuario'@'localhost' IDENTIFIED BY 'contraseña_segura';

-- Dar permisos
GRANT ALL PRIVILEGES ON mi_app.* TO 'mi_usuario'@'localhost';

-- Aplicar cambios
FLUSH PRIVILEGES;

Permisos específicos

-- Solo lectura
GRANT SELECT ON mi_app.* TO 'usuario_lectura'@'localhost';

-- Lectura y escritura
GRANT SELECT, INSERT, UPDATE, DELETE ON mi_app.* TO 'usuario_app'@'localhost';

-- Ver permisos
SHOW GRANTS FOR 'mi_usuario'@'localhost';

-- Revocar permisos
REVOKE ALL PRIVILEGES ON mi_app.* FROM 'mi_usuario'@'localhost';

-- Eliminar usuario
DROP USER 'mi_usuario'@'localhost';

Acceso remoto (si es necesario)

-- Crear usuario para acceso remoto
CREATE USER 'mi_usuario'@'%' IDENTIFIED BY 'contraseña_segura';
GRANT ALL PRIVILEGES ON mi_app.* TO 'mi_usuario'@'%';
FLUSH PRIVILEGES;
# En configuración, cambiar bind-address
bind-address = 0.0.0.0
# Abrir firewall
sudo ufw allow from IP_PERMITIDA to any port 3306

Optimización de rendimiento

Tunning de MySQL en VPS

Calcular innodb_buffer_pool_size

La variable más importante. Debe ser ~70-80% de la RAM disponible para servidores dedicados a MySQL.

# Ver RAM disponible
free -h

# Fórmula para VPS compartido (MySQL + web)
# innodb_buffer_pool_size = RAM * 0.25 a 0.40
# 2GB RAM → 512M a 800M
# 4GB RAM → 1G a 1.5G
# 8GB RAM → 2G a 3G

Configuración por tamaño de VPS

VPS 2GB RAM:

innodb_buffer_pool_size = 512M
innodb_log_file_size = 128M
max_connections = 100
tmp_table_size = 32M
max_heap_table_size = 32M

VPS 4GB RAM:

innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
max_connections = 150
tmp_table_size = 64M
max_heap_table_size = 64M

VPS 8GB RAM:

innodb_buffer_pool_size = 2G
innodb_log_file_size = 512M
max_connections = 200
tmp_table_size = 128M
max_heap_table_size = 128M

Verificar uso actual

-- Ver variables actuales
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'max_connections';

-- Ver estado
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Innodb_buffer_pool%';

-- Conexiones usadas vs máximas
SHOW STATUS LIKE 'Max_used_connections';

Queries lentas

Habilitar log de queries lentas

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1

Analizar queries lentas

# Ver queries lentas
sudo tail -100 /var/log/mysql/slow.log

# Usar mysqldumpslow
sudo mysqldumpslow -s t /var/log/mysql/slow.log | head -20

Optimizar queries

-- Analizar query específica
EXPLAIN SELECT * FROM usuarios WHERE email = '[email protected]';

-- Ver índices de tabla
SHOW INDEX FROM usuarios;

-- Crear índice
CREATE INDEX idx_email ON usuarios(email);

-- Ver tablas sin índices usados
SELECT * FROM sys.schema_tables_with_full_table_scans;

Índices

Cuándo crear índices

  • Columnas en WHERE frecuentes
  • Columnas en JOIN
  • Columnas en ORDER BY
  • Columnas en GROUP BY

Crear índices

-- Índice simple
CREATE INDEX idx_nombre ON tabla(columna);

-- Índice compuesto (orden importa)
CREATE INDEX idx_compuesto ON tabla(columna1, columna2);

-- Índice único
CREATE UNIQUE INDEX idx_email ON usuarios(email);

-- Ver índices
SHOW INDEX FROM tabla;

-- Eliminar índice
DROP INDEX idx_nombre ON tabla;

Analizar uso de índices

-- Estadísticas de índices
SELECT 
    table_name,
    index_name,
    stat_value
FROM mysql.innodb_index_stats 
WHERE database_name = 'mi_app';

Backups

mysqldump (básico)

# Backup de una base de datos
mysqldump -u root -p mi_app > backup.sql

# Con compresión
mysqldump -u root -p mi_app | gzip > backup.sql.gz

# Todas las bases de datos
mysqldump -u root -p --all-databases > all_backup.sql

# Opciones recomendadas
mysqldump -u root -p \
    --single-transaction \
    --routines \
    --triggers \
    --events \
    mi_app | gzip > backup_$(date +%Y%m%d).sql.gz

Restaurar backup

# Restaurar
mysql -u root -p mi_app < backup.sql

# Desde comprimido
gunzip < backup.sql.gz | mysql -u root -p mi_app

# Crear base de datos primero si no existe
mysql -u root -p -e "CREATE DATABASE mi_app"
mysql -u root -p mi_app < backup.sql

Script de backup automatizado

#!/bin/bash
# /root/scripts/mysql-backup.sh

FECHA=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/mysql"
RETENTION_DAYS=7

mkdir -p $BACKUP_DIR

# Backup de todas las bases de datos
mysqldump --all-databases \
    --single-transaction \
    --routines \
    --triggers \
    | gzip > $BACKUP_DIR/all_databases_$FECHA.sql.gz

# Eliminar backups antiguos
find $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete

echo "Backup completado: $BACKUP_DIR/all_databases_$FECHA.sql.gz"
chmod +x /root/scripts/mysql-backup.sh

# Cron diario a las 3 AM
0 3 * * * /root/scripts/mysql-backup.sh >> /var/log/mysql-backup.log 2>&1

Monitorización

Comandos útiles

-- Conexiones actuales
SHOW PROCESSLIST;

-- Conexiones completas
SHOW FULL PROCESSLIST;

-- Estado general
SHOW STATUS;

-- Variables de configuración
SHOW VARIABLES;

-- Estado de InnoDB
SHOW ENGINE INNODB STATUS\G

-- Tamaño de bases de datos
SELECT 
    table_schema AS 'Base de datos',
    ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Tamaño (MB)'
FROM information_schema.tables
GROUP BY table_schema
ORDER BY SUM(data_length + index_length) DESC;

Script de monitorización

#!/bin/bash
# /root/scripts/mysql-status.sh

echo "=== MySQL Status ==="
echo ""

echo "=== Conexiones ==="
mysql -e "SHOW STATUS LIKE 'Threads_connected';"
mysql -e "SHOW STATUS LIKE 'Max_used_connections';"

echo ""
echo "=== Buffer Pool ==="
mysql -e "SHOW STATUS LIKE 'Innodb_buffer_pool_read%';"

echo ""
echo "=== Queries ==="
mysql -e "SHOW STATUS LIKE 'Queries';"
mysql -e "SHOW STATUS LIKE 'Slow_queries';"

Problemas comunes

”Too many connections"

-- Ver conexiones actuales
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';

-- Aumentar temporalmente
SET GLOBAL max_connections = 200;

-- Permanente en configuración
max_connections = 200

"Lock wait timeout exceeded”

-- Ver locks actuales
SHOW ENGINE INNODB STATUS\G

-- Ver transacciones
SELECT * FROM information_schema.innodb_trx;

-- Matar proceso bloqueado
KILL proceso_id;

MySQL consume mucha RAM

# Reducir buffer pool
innodb_buffer_pool_size = 256M

# Reducir conexiones
max_connections = 50

# Reducir buffers por conexión
sort_buffer_size = 256K
read_buffer_size = 256K
join_buffer_size = 256K

Queries muy lentas

-- Identificar queries lentas
SELECT * FROM sys.statements_with_full_table_scans 
ORDER BY no_index_used_count DESC LIMIT 10;

-- Verificar índices
EXPLAIN SELECT ... ;

-- Optimizar tablas
OPTIMIZE TABLE nombre_tabla;

-- Analizar tablas
ANALYZE TABLE nombre_tabla;

Seguridad

Checklist de seguridad

# 1. Ejecutar mysql_secure_installation
sudo mysql_secure_installation

# 2. Verificar usuarios
mysql -e "SELECT user, host FROM mysql.user;"

# 3. Eliminar usuarios innecesarios
mysql -e "DROP USER ''@'localhost';"

# 4. Solo acceso local (bind-address = 127.0.0.1)

# 5. Firewall si acceso remoto necesario
sudo ufw allow from IP_ESPECIFICA to any port 3306

Contraseñas seguras

-- Cambiar contraseña
ALTER USER 'usuario'@'localhost' IDENTIFIED BY 'nueva_contraseña_segura';

-- Política de contraseñas (MySQL 8.0+)
SHOW VARIABLES LIKE 'validate_password%';

Preguntas frecuentes

¿Cuánta RAM debo asignar a innodb_buffer_pool_size?

Para VPS con MySQL + web server, usa 25-40% de la RAM. Para servidor dedicado a MySQL, usa 70-80%. En un VPS de 4GB compartido, 1GB es un buen punto de partida.

¿MySQL o MariaDB para mi VPS?

MariaDB para la mayoría de casos. Es compatible 100% con MySQL, ligeramente más rápido, y totalmente open source. Solo elige MySQL si tienes requisitos específicos de Oracle.

¿Cómo sé si necesito más conexiones?

Ejecuta 'SHOW STATUS LIKE Max_used_connections'. Si está cerca del max_connections configurado, aumenta. Pero primero optimiza queries y cierra conexiones que no se usan.

¿Cada cuánto debo hacer backup de MySQL?

Mínimo diario para producción. Para datos críticos, considera backups cada pocas horas o replicación en tiempo real.

¿Por qué mis queries son lentas aunque tengo índices?

Usa EXPLAIN para verificar que el índice se está usando. A veces MySQL elige no usar el índice si la selectividad es baja. También verifica que las estadísticas de tabla estén actualizadas con ANALYZE TABLE.

Nuestra recomendación

Configuración inicial:

  1. Ejecutar mysql_secure_installation
  2. Ajustar innodb_buffer_pool_size según RAM
  3. Habilitar slow query log
  4. Configurar backups automáticos

Para optimizar:

  • Analiza queries lentas regularmente
  • Crea índices en columnas frecuentes en WHERE
  • Monitoriza conexiones y memoria

¿Necesitas bases de datos gestionadas? La administración gestionada de Avantys incluye optimización y backups de MySQL.


Conclusión

MySQL bien configurado es la diferencia entre un sitio lento y uno rápido. Dedica tiempo a ajustar innodb_buffer_pool_size, crear índices adecuados y monitorizar queries lentas.

Recuerda: backups automáticos son obligatorios, no opcionales.

¿Necesitas un VPS optimizado para bases de datos? Explora los VPS de Avantys con almacenamiento NVMe para máximo rendimiento.


¿Quieres que lo hagamos por ti?

En Avantys gestionamos tu web, hosting y crecimiento digital de punta a punta. Tú a lo importante.

Hablar con Avantys
// Boletín

Suscríbete al boletín

Guías nuevas, sin spam. Cancela cuando quieras.