Introduction
After a MySQL server restart, PHP applications using PDO may fail to connect with "SQLSTATE[HY000] [2002] Connection refused". This happens because the MySQL socket file may have been removed or moved, the server may not have fully initialized, or the PHP configuration references a stale socket path.
This is particularly common in development environments, Docker setups, and automated deployment pipelines.
Symptoms
- PDO throws "SQLSTATE[HY000] [2002] Connection refused" after MySQL restart
- Error shows "No such file or directory" for the MySQL socket path
- Application works again after restarting PHP-FPM or the web server
Common Causes
- MySQL socket file path changed after restart (different version or config)
- MySQL is not fully ready when PHP attempts to connect (race condition)
- PHP cached the old socket path in OPcache or connection pool
Step-by-Step Fix
- 1.Verify MySQL is running and listening: Check the server status and connection method.
- 2.```bash
- 3.# Check if MySQL is running:
- 4.systemctl status mysql
# Check what port/socket MySQL is using: mysql -u root -e "SHOW VARIABLES LIKE 'socket';" # Output: /var/run/mysqld/mysqld.sock
# Check if MySQL is listening: ss -tlnp | grep 3306 ```
- 1.Use TCP connection instead of socket for reliability: Connect via 127.0.0.1 instead of localhost.
- 2.```php
- 3.<?php
- 4.// BAD: Uses socket when host is 'localhost'
- 5.$pdo = new PDO('mysql:host=localhost;dbname=myapp', 'user', 'pass');
// GOOD: Uses TCP connection (more reliable across restarts) $pdo = new PDO( 'mysql:host=127.0.0.1;port=3306;dbname=myapp;charset=utf8mb4', 'user', 'pass', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ] ); ```
- 1.Add connection retry logic for transient failures: Retry during server startup window.
- 2.```php
- 3.<?php
- 4.function connectWithRetry(string $dsn, string $user, string $pass, int $maxRetries = 5): PDO {
- 5.for ($i = 1; $i <= $maxRetries; $i++) {
- 6.try {
- 7.return new PDO($dsn, $user, $pass, [
- 8.PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
- 9.PDO::ATTR_TIMEOUT => 5,
- 10.]);
- 11.} catch (PDOException $e) {
- 12.if ($i === $maxRetries) {
- 13.throw new RuntimeException(
- 14."Database connection failed after $maxRetries retries: {$e->getMessage()}"
- 15.);
- 16.}
- 17.sleep($i); // Exponential-ish backoff
- 18.}
- 19.}
- 20.}
- 21.
`
Prevention
- Use 127.0.0.1 instead of localhost to force TCP connections
- Add connection retry logic for infrastructure startup scenarios
- Use health checks to verify MySQL is ready before starting PHP-FPM
- Configure proper systemd service ordering (mysql before php-fpm)