Tutoriales de VPS
MySQL / MariaDB no conecta en un VPS (2026): solución de problemas del puerto 3306, bind-address, privilegios y fallos de arranque del servicio
Cuando MySQL o MariaDB no conecta en un VPS, la causa habitual no es una sola: el servicio no está iniciado, el 3306 no está escuchando, bind-address solo se vincula a localhost, el firewall/grupo de seguridad lo bloquea, los privilegios del usuario son incorrectos, el disco está lleno o InnoDB no arranca. Este artículo diagnostica capa por capa: conexión local, escucha de puertos, logs, acceso remoto y estado de la base de datos.

Cuando MySQL o MariaDB no conecta, muchos sitios web se caen directamente.
WordPress muestra:
Error establishing a database connection
En el log de la aplicación puede aparecer:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket
ERROR 2003 (HY000): Can't connect to MySQL server on 'x.x.x.x'
Access denied for user
Connection refused
Lost connection to MySQL server
Todos estos errores parecen "la base de datos está rota", pero la causa raíz puede ser completamente distinta: el servicio no está iniciado, el puerto no está escuchando, la ruta del socket es incorrecta, el disco está lleno, MySQL solo escucha en 127.0.0.1, el firewall bloquea el 3306, los privilegios del usuario son incorrectos o incluso InnoDB no arranca.
Este artículo sigue un orden de diagnóstico: primero distingue si falla la conexión local o la conexión remota, y luego revisa el servicio, el puerto, los logs, los privilegios y el disco. No abras el 3306 a internet público de inmediato ni reinstales la base de datos directamente.
Primero prueba en el propio VPS:
mysql -u root -p
O:
mysqladmin -u root -p ping
Si tampoco puedes conectar localmente, revisa primero el servicio y los logs.
Si puedes conectar localmente pero un equipo remoto no:
mysql -h 你的VPS_IP -P 3306 -u 用户名 -p
Entonces céntrate en la dirección de escucha, el firewall, el grupo de seguridad y los privilegios del usuario.
Este paso es clave. Muchas personas no pueden conectar en remoto y van a cambiar la contraseña de la base de datos; en realidad la conexión local funciona bien y el problema está en la capa de red. Otras no pueden conectar ni localmente y siguen trasteando con el grupo de seguridad, una dirección completamente equivocada.
En Ubuntu/Debian el nombre del servicio puede ser mysql o mariadb.
Primero mira:
systemctl status mysql --no-pager
systemctl status mariadb --no-pager
Si no estás seguro del nombre del servicio:
systemctl list-units | grep -Ei 'mysql|mariadb'
Mira los logs recientes:
journalctl -u mysql --since "30 minutes ago" --no-pager
journalctl -u mariadb --since "30 minutes ago" --no-pager
Si el servicio no está iniciado, primero intenta:
sudo systemctl restart mysql
O:
sudo systemctl restart mariadb
Después de reiniciar, no te limites a ver si el comando devolvió algo; vuelve a mirar el estado y los logs. Muchos fallos de arranque de MySQL/MariaDB tienen la causa real escrita en los logs.
Ubicaciones habituales del log:
/var/log/mysql/error.log
/var/log/mariadb/mariadb.log
/var/log/mysql/mysql.log
Puedes buscarlo así:
sudo ls -lh /var/log/mysql/ /var/log/mariadb/ 2>/dev/null
sudo tail -n 100 /var/log/mysql/error.log
Si este archivo no existe, también puedes usar journal:
journalctl -u mysql -n 100 --no-pager
journalctl -u mariadb -n 100 --no-pager
Palabras clave habituales:
| Palabra clave del log | Dirección habitual |
|---|---|
No space left on device | Disco o inodos llenos |
Can't create/write to file | Problemas de permisos, disco o directorio temporal |
InnoDB: Database was not shutdown normally | Recuperación tras un apagado anómalo |
InnoDB: Unable to lock ./ibdata1 | Otro proceso mysqld o bloqueo de archivo |
Bind on TCP/IP port: Address already in use | El 3306 está ocupado |
Access denied for user | Problemas de usuario, contraseña o privilegios |
Too many connections | Límite de conexiones alcanzado |
Los logs son más fiables que las suposiciones. Mira primero los logs y luego decide el siguiente paso.
MySQL/MariaDB es muy sensible al disco. Un disco de sistema lleno, inodos llenos o un /tmp en el que no se puede escribir pueden provocar fallos de arranque o de escritura.
Primero mira:
df -h
df -i
Luego mira el tamaño del directorio de la base de datos:
sudo du -h --max-depth=1 /var/lib/mysql | sort -h
Si el disco está lleno, no borres /var/lib/mysql sin cuidado. Ese es el directorio de datos de la base de datos; borrar lo incorrecto significa pérdida de datos.
Puedes priorizar la limpieza de:
sudo apt clean
journalctl --disk-usage
sudo journalctl --vacuum-time=7d
Si los binlogs de MySQL son grandes, tampoco hagas rm directamente. Primero entra en MySQL y consulta:
SHOW BINARY LOGS;
Luego decide si limpiar según la situación de copias de seguridad y replicación. Si no estás seguro, haz primero una instantánea o una copia de seguridad.
Si el servicio aparece como running pero no puedes conectar desde fuera, mira primero el puerto:
ss -lntp | grep 3306
Puede que veas:
127.0.0.1:3306
0.0.0.0:3306
[::]:3306
La diferencia es importante:
127.0.0.1:3306: solo permite conexiones locales0.0.0.0:3306: escucha en todas las direcciones IPv4[::]:3306: escucha en IPv6; el comportamiento exacto depende de la configuración
Si solo tienes WordPress y MySQL en el mismo VPS, 127.0.0.1 es en realidad más seguro y no necesitas abrirlo a internet público.
Si realmente necesitas conexiones remotas, por ejemplo con el servidor de aplicaciones y la base de datos separados, entonces considera hacer que MySQL escuche en una IP interna o en una IP pública específica.
La dirección de escucha de MySQL/MariaDB normalmente la controla bind-address.
Consulta la configuración:
sudo grep -R "bind-address" /etc/mysql/ /etc/my.cnf* 2>/dev/null
Configuraciones habituales:
bind-address = 127.0.0.1
Si quieres permitir conexiones remotas, podrías cambiarlo a:
bind-address = 0.0.0.0
Pero aquí hay que tener mucho cuidado. 0.0.0.0 significa escuchar en todas las interfaces de red, lo que no equivale a permitir el acceso de forma segura. También debes combinarlo con firewall, grupo de seguridad y privilegios de usuario, permitiendo el acceso solo desde IP de confianza.
Es más recomendable vincular a una dirección interna, por ejemplo:
bind-address = 10.0.0.5
Reinicia tras el cambio:
sudo systemctl restart mysql
ss -lntp | grep 3306
Cuando no puedes conectar al 3306 en remoto, a menudo no es MySQL en sí, sino el firewall o el grupo de seguridad del proveedor cloud.
Firewall local:
sudo ufw status verbose
sudo iptables -S
Si usas firewalld:
sudo firewall-cmd --list-all
También revisa el grupo de seguridad del proveedor cloud:
- Si se permite el 3306 entrante
- Si la IP de origen está restringida a tu servidor de aplicaciones o IP de oficina
- Si se usó el protocolo o la interfaz de red equivocados
- Si solo se permitió IPv4 mientras el tráfico va realmente por IPv6
No abras el 3306 directamente a 0.0.0.0/0. Exponer una base de datos a internet público es muy arriesgado; los ataques de fuerza bruta y los escaneos la encontrarán rápidamente.
Si solo es para administración temporal, prioriza un túnel SSH:
ssh -L 3307:127.0.0.1:3306 root@你的VPS_IP
Luego conecta localmente:
mysql -h 127.0.0.1 -P 3307 -u 用户名 -p
Así la base de datos sigue escuchando solo en local y el acceso remoto va por un túnel SSH cifrado.
Los usuarios de MySQL se distinguen por 用户名@来源主机. app@localhost y app@% son dos autorizaciones distintas.
Tras entrar en MySQL, mira los usuarios:
SELECT user, host FROM mysql.user;
Consulta los privilegios:
SHOW GRANTS FOR 'app'@'localhost';
SHOW GRANTS FOR 'app'@'%';
Si la IP del servidor de aplicaciones remoto es 10.0.0.8, lo más seguro es autorizar solo ese origen:
CREATE USER 'app'@'10.0.0.8' IDENTIFIED BY '强密码';
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app'@'10.0.0.8';
FLUSH PRIVILEGES;
No hagas esto directamente para ahorrarte esfuerzo:
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password';
Este tipo de configuración es un foco habitual de incidentes. Da al usuario de la aplicación solo las bases de datos y privilegios que necesita, y no expongas root en remoto.
Si aparece:
Access denied for user 'app'@'x.x.x.x'
Revisa especialmente:
- Si el nombre de usuario es correcto
- Si la contraseña es correcta
- Si
hostcoincide con la IP de origen - Si la aplicación se conecta a la instancia de base de datos correcta
- Si el plugin de autenticación de MySQL 8 es compatible con el cliente
Mira el usuario actual:
SELECT user, host, plugin FROM mysql.user;
El plugin de autenticación predeterminado de MySQL 8 puede hacer que clientes antiguos sean incompatibles. No cambies root a ciegas; puedes configurar un plugin compatible solo para el usuario de la aplicación, o actualizar el cliente.
Si el log o la aplicación muestra:
Too many connections
Primero mira las conexiones actuales:
SHOW PROCESSLIST;
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';
Puedes subirlo temporalmente:
SET GLOBAL max_connections = 200;
Pero esto es solo temporal. A largo plazo revisa:
- Si el pool de conexiones de la aplicación está configurado demasiado grande
- Si hay consultas lentas que bloquean conexiones
- Si hay tráfico de rastreadores o ataques
- Si el número de procesos PHP-FPM/aplicación supera la capacidad de la base de datos
- Si la máquina de la base de datos tiene suficiente memoria
En un VPS pequeño, poner max_connections a 1000 a ciegas puede reventar la memoria directamente.
Si MySQL/MariaDB se ejecuta en Docker, mira primero el contenedor:
docker ps
docker logs 容器名 --tail 100
docker compose ps
docker compose logs --tail 100 mysql
Mira el mapeo de puertos:
docker ps --format 'table {{.Names}}\t{{.Ports}}'
Prueba dentro del contenedor:
docker exec -it 容器名 mysql -u root -p
Prueba en el host:
mysql -h 127.0.0.1 -P 3306 -u root -p
Errores habituales de Docker:
- Permisos incorrectos del volumen de datos
- Directorio de datos montado incorrectamente
- Las variables de entorno solo surten efecto en la primera inicialización; cambiarlas después no sirve
- La escucha dentro del contenedor funciona, pero el puerto no está mapeado al host
- El contenedor de la aplicación debería conectar al nombre de servicio
mysqlpero conecta a127.0.0.1
En escenarios Docker, 127.0.0.1 es relativo al propio contenedor, no necesariamente al host.
Si el sitio web informa de un fallo de conexión a la base de datos, normalmente lo reviso así:
systemctl status mysql --no-pager
systemctl status mariadb --no-pager
journalctl -u mysql --since "30 minutes ago" --no-pager
sudo tail -n 100 /var/log/mysql/error.log
Mira el disco:
df -h
df -i
sudo du -h --max-depth=1 /var/lib/mysql | sort -h
Mira el puerto:
ss -lntp | grep 3306
Conexión local:
mysqladmin -u root -p ping
mysql -u root -p
Solo para acceso remoto, revisa:
sudo ufw status verbose
sudo iptables -S
sudo grep -R "bind-address" /etc/mysql/ /etc/my.cnf* 2>/dev/null
Tras entrar en MySQL, consulta:
SELECT user, host, plugin FROM mysql.user;
SHOW PROCESSLIST;
SHOW VARIABLES LIKE 'max_connections';
Con este orden, básicamente puedes clasificar el problema en servicio, disco, escucha, red, privilegios o número de conexiones.
- Si el
mysql -u root -plocal puede conectar - Si
systemctl status mysql/mariadbes normal - Si
journalctly error.log tienen errores claros - Si
df -hydf -ison normales - Si
/var/lib/mysqlha crecido de forma anómala - Si
ss -lntp | grep 3306está escuchando - Si
bind-addresscoincide con lo esperado - Si UFW / iptables / firewalld está bloqueando
- Si el grupo de seguridad del proveedor cloud solo permite IP de confianza
- Si el
user@hostdel usuario de MySQL coincide con el origen - Si hay
Too many connections - En escenarios Docker, si se revisaron los logs del contenedor, el mapeo de puertos y los volúmenes de datos
- No se expuso el 3306 sin protección a toda la red
Lo peor de los problemas de conexión a la base de datos es revisar las cosas mezcladas. Si no puedes conectar localmente, revisa primero el servicio y los logs; si puedes conectar localmente pero no en remoto, revisa entonces la escucha, el firewall, el grupo de seguridad y los privilegios. Con solo separar estas capas, los fallos de conexión de MySQL/MariaDB dejan de ser cosa de magia.