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. 1.Verify MySQL is running and listening: Check the server status and connection method.
  2. 2.```bash
  3. 3.# Check if MySQL is running:
  4. 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. 1.Use TCP connection instead of socket for reliability: Connect via 127.0.0.1 instead of localhost.
  2. 2.```php
  3. 3.<?php
  4. 4.// BAD: Uses socket when host is 'localhost'
  5. 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. 1.Add connection retry logic for transient failures: Retry during server startup window.
  2. 2.```php
  3. 3.<?php
  4. 4.function connectWithRetry(string $dsn, string $user, string $pass, int $maxRetries = 5): PDO {
  5. 5.for ($i = 1; $i <= $maxRetries; $i++) {
  6. 6.try {
  7. 7.return new PDO($dsn, $user, $pass, [
  8. 8.PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  9. 9.PDO::ATTR_TIMEOUT => 5,
  10. 10.]);
  11. 11.} catch (PDOException $e) {
  12. 12.if ($i === $maxRetries) {
  13. 13.throw new RuntimeException(
  14. 14."Database connection failed after $maxRetries retries: {$e->getMessage()}"
  15. 15.);
  16. 16.}
  17. 17.sleep($i); // Exponential-ish backoff
  18. 18.}
  19. 19.}
  20. 20.}
  21. 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)