SQLSTATE error de conexión a base de datos en Laravel
SQLSTATE error de conexión a base de datos en Laravel
Pocos errores en Laravel son tan frustrantes como los de conexión a base de datos. Aparecen en el momento más inoportuno y el mensaje de error suele ser críptico para alguien que no está familiarizado con los códigos SQLSTATE. En esta guía vamos a ver los errores SQLSTATE más comunes, qué significan exactamente y cómo solucionarlos.
Entendiendo los códigos SQLSTATE
Los errores SQLSTATE son códigos estandarizados que PDO (la capa de abstracción de base de datos de PHP) usa para comunicar errores. Tienen la forma SQLSTATE[XXXXX] seguido de un mensaje más descriptivo.
Los más comunes en Laravel son:
SQLSTATE[HY000] [2002]— No se puede conectar (servidor apagado, host incorrecto)SQLSTATE[HY000] [1045]— Acceso denegado (credenciales incorrectas)SQLSTATE[HY000] [1049]— Base de datos desconocida (la BD no existe)SQLSTATE[42S02]— Tabla no encontradaSQLSTATE[23000]— Violación de integridad (duplicate key, foreign key)
Veamos cada uno en detalle.
Error SQLSTATE[HY000] [2002]: Connection refused / No such file or directory
Este es el error más común y significa que PHP no puede conectarse al servidor de base de datos. Las causas posibles son:
Causa 1: MySQL no está corriendo
SQLSTATE[HY000] [2002] Connection refused
Verifica si MySQL está corriendo:
// En Ubuntu/Linux:
sudo systemctl status mysql
// Si está parado, inícialo:
sudo systemctl start mysql
// Para que arranque automáticamente al iniciar el servidor:
sudo systemctl enable mysql
En macOS:
// Con Homebrew:
brew services list | grep mysql
brew services start mysql
// Con MySQL.app: ábrelo y activa el servicio desde la interfaz
Causa 2: El host en el .env es incorrecto
// Verifica estas líneas en tu .env:
DB_HOST=127.0.0.1
DB_PORT=3306
En macOS, especialmente con MySQL instalado mediante Homebrew o DBngin, a veces el problema es que PHP intenta conectar por socket de Unix cuando usas localhost, pero el socket no está donde PHP lo busca. Usa 127.0.0.1 (IP) en lugar de localhost para forzar la conexión TCP:
DB_HOST=127.0.0.1 // Fuerza conexión TCP
// En lugar de:
DB_HOST=localhost // Puede intentar conexión por socket
Causa 3: El puerto es incorrecto
Si MySQL está corriendo en un puerto diferente al estándar (3306):
// Verifica en qué puerto está MySQL:
sudo netstat -tlnp | grep mysql
// O:
sudo ss -tlnp | grep mysql
// Ajusta el puerto en .env:
DB_PORT=3307 // Si está en 3307
Causa 4: Con Laravel Sail/Docker, el host es incorrecto
Dentro de los contenedores Docker, 127.0.0.1 no apunta al servicio MySQL del host, sino al propio contenedor. Debes usar el nombre del servicio definido en docker-compose.yml:
// En .env cuando usas Sail:
DB_HOST=mysql // No 127.0.0.1
Error SQLSTATE[HY000] [1045]: Access denied for user
SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES)
Este error significa que el usuario y/o la contraseña son incorrectos.
Solución 1: Verificar las credenciales
Primero, intenta conectarte manualmente desde la terminal para verificar que las credenciales son correctas:
mysql -u tu_usuario -p -h 127.0.0.1
// Introduce la contraseña cuando te la pida
// Si puedes conectar, las credenciales son correctas
Solución 2: Limpiar la caché de configuración
Una causa muy común que se pasa por alto: tienes credenciales correctas en el .env, pero la caché de configuración tiene las credenciales antiguas:
php artisan config:clear
php artisan cache:clear
Después de limpiar la caché, vuelve a intentar la conexión.
Solución 3: El usuario no existe o no tiene permisos
// Conéctate como root:
sudo mysql -u root
// Verifica que el usuario existe:
SELECT user, host FROM mysql.user;
// Si no existe, créalo:
CREATE USER 'mi_usuario'@'localhost' IDENTIFIED BY 'mi_password';
GRANT ALL PRIVILEGES ON mi_base_de_datos.* TO 'mi_usuario'@'localhost';
FLUSH PRIVILEGES;
Nota el @'localhost' vs @'127.0.0.1': en MySQL, localhost y 127.0.0.1 son tratados como hosts diferentes. Si tu aplicación conecta por 127.0.0.1, el usuario debe tener permisos para 'usuario'@'127.0.0.1':
GRANT ALL PRIVILEGES ON mi_base_de_datos.* TO 'mi_usuario'@'127.0.0.1';
FLUSH PRIVILEGES;
Solución 4: Cambiar la contraseña del usuario
// En MySQL:
ALTER USER 'mi_usuario'@'localhost' IDENTIFIED BY 'nueva_password';
FLUSH PRIVILEGES;
Error SQLSTATE[HY000] [1049]: Unknown database
SQLSTATE[HY000] [1049] Unknown database 'mi_base_de_datos'
La base de datos que especificaste en DB_DATABASE no existe. Créala:
// En MySQL:
CREATE DATABASE mi_base_de_datos CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
O verifica el nombre correcto en el .env:
// Si la base de datos se llama "mi_proyecto_db" pero escribiste "mi_proyecto":
DB_DATABASE=mi_proyecto_db // Nombre exacto de la base de datos
Error SQLSTATE[42S02]: Table not found
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'mi_bd.products' doesn't exist
La tabla no existe. Esto suele ocurrir porque:
- No has ejecutado las migraciones
- Ejecutaste las migraciones en una base de datos diferente
- Alguien borró la tabla manualmente
Solución:
// Ejecutar las migraciones pendientes:
php artisan migrate
// Ver el estado de las migraciones:
php artisan migrate:status
// Si necesitas recrear todo desde cero (en desarrollo):
php artisan migrate:fresh --seed
Error SQLSTATE[23000]: Integrity constraint violation
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'valor' for key 'PRIMARY'
Estás intentando insertar un valor que ya existe en una columna con restricción de unicidad (PRIMARY KEY o UNIQUE).
En Laravel, esto suele ocurrir cuando:
- Ejecutas seeders más de una vez sin limpiar los datos previos
- Intentas crear un registro con un email que ya existe
// En lugar de crear y fallar, usa firstOrCreate:
$usuario = User::firstOrCreate(
['email' => 'usuario@ejemplo.com'],
['name' => 'Juan', 'password' => bcrypt('password')]
);
// O updateOrCreate para actualizar si existe:
$usuario = User::updateOrCreate(
['email' => 'usuario@ejemplo.com'],
['name' => 'Juan García']
);
Metodología de diagnóstico
Cuando encuentres un error de conexión, sigue estos pasos en orden:
Paso 1: Limpia la caché de configuración
php artisan config:clear
Este es siempre el primer paso. La caché puede tener valores desactualizados.
Paso 2: Verifica el .env
Abre .env y verifica que cada valor es correcto. Un error tipográfico en la contraseña es más común de lo que parece.
Paso 3: Verifica que MySQL está corriendo
// Linux:
sudo systemctl status mysql
// macOS:
brew services list
Paso 4: Prueba la conexión desde la terminal
mysql -u tu_usuario -p -h 127.0.0.1 nombre_base_datos
Si este comando funciona, la configuración de MySQL es correcta y el problema es en Laravel (probablemente la caché).
Paso 5: Verifica la conexión desde Tinker
php artisan tinker
Dentro de Tinker:
// Verificar la conexión
DB::connection()->getPdo();
// Si hay error, verás el mensaje completo
// Si funciona, verás el objeto PDO
// Ver qué configuración está usando Laravel actualmente:
config('database.connections.mysql');
// Esto muestra todos los parámetros de conexión que Laravel está usando
Paso 6: Añadir logging de errores temporalmente
Si aún no puedes identificar el problema, añade logging temporal:
// En AppServiceProvider::boot() o en una ruta de prueba:
try {
DB::connection()->getPdo();
echo "Conexión exitosa a: " . DB::connection()->getDatabaseName();
} catch (\Exception $e) {
echo "Error de conexión: " . $e->getMessage();
}
Problema específico: conexión por socket en macOS
En macOS con MySQL instalado vía Homebrew, PHP puede intentar conectar por socket de Unix en lugar de TCP. El socket suele estar en /tmp/mysql.sock con Homebrew y en /var/run/mysqld/mysqld.sock en Linux.
Si tienes el error [2002] No such file or directory, puede que sea el socket:
// Opción 1: forzar TCP con 127.0.0.1
DB_HOST=127.0.0.1
// Opción 2: especificar el socket directamente
// En config/database.php:
'mysql' => [
'driver' => 'mysql',
'unix_socket' => env('DB_SOCKET', '/tmp/mysql.sock'),
// ... resto de la configuración
],
// Y en .env:
DB_SOCKET=/tmp/mysql.sock
Puedes encontrar la ubicación del socket ejecutando:
mysql -u root -e "SHOW VARIABLES LIKE 'socket';"
Configuración en Docker/Sail
Si usas Laravel Sail, recuerda que la conexión de base de datos se hace entre contenedores, no entre tu máquina y un servicio local:
// .env correcto para Sail:
DB_CONNECTION=mysql
DB_HOST=mysql // Nombre del servicio en docker-compose.yml
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=sail
DB_PASSWORD=password
Si intentas conectarte con 127.0.0.1 dentro del contenedor, estarás intentando conectar al contenedor mismo, no al servicio MySQL.
Conclusión
Los errores SQLSTATE en Laravel tienen siempre una causa identificable. El proceso de diagnóstico es sistemático: primero limpia la caché de configuración, luego verifica que el servidor de base de datos está corriendo, después confirma las credenciales conectándote directamente con MySQL desde la terminal, y finalmente usa Tinker para verificar la conexión desde Laravel.
La clave está en no asumir nada: verifica cada componente de la cadena de conexión por separado hasta encontrar dónde está la rotura.