Matched signals
- ERROR 2003 (HY000)
- ERROR 2002 (HY000)
- Can't connect to MySQL server on
- Can't connect to local MySQL server through socket
- SQLSTATE[HY000] [2002]
- _mysql_exceptions.OperationalError: (2003,
- CommunicationsException: Communications link failure
- MySQLNonTransientConnectionException
MySQL connection refused or service unavailable
What this failure means
The application or test suite could not connect to MySQL. The service is not running, has not finished starting, or the connection string points to the wrong host or port.
Symptoms
Faultline looks for one or more of these log fragments:
ERROR 2003 (HY000)
ERROR 2002 (HY000)
Can't connect to MySQL server on
Can't connect to local MySQL server through socket
SQLSTATE[HY000] [2002]
_mysql_exceptions.OperationalError: (2003,
CommunicationsException: Communications link failure
MySQLNonTransientConnectionException
Diagnosis
MySQL connection failures in CI occur when:
- The MySQL service container has not finished initializing before the application or test runner attempts its first connection.
- The hostname is wrong — for example,
localhostis used instead of the service name (mysql,db) in a Docker Compose or GitHub Actions services block. - The port is misconfigured or blocked. MySQL listens on
3306by default. - Credentials, database name, or user permissions are incorrect.
- The service definition is missing from the CI workflow entirely.
The MySQL client emits error code 2003 (TCP connection refused) or 2002
(socket file not found) along with the HY000 SQLSTATE, or a driver-level
equivalent such as SQLSTATE[HY000] [2002] Connection refused (PHP/PDO) or
CommunicationsException: Communications link failure (Java).
Fix steps
-
Verify MySQL is accepting connections:
mysqladmin ping -h 127.0.0.1 -P 3306 -u root -ppassword -
Check the service hostname. In Docker Compose and GitHub Actions services blocks, connect using the service name — not
localhost:GitHub Actions example:
services: mysql: image: mysql:8 env: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: testdb options: >- --health-cmd="mysqladmin ping -h 127.0.0.1" --health-interval=10s --health-retries=5Then connect to
127.0.0.1(notlocalhost) because the service is port-mapped, not on a shared Docker network. -
For Docker Compose, add a healthcheck dependency:
services: mysql: image: mysql:8 environment: MYSQL_ROOT_PASSWORD: secret healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s retries: 5 app: depends_on: mysql: condition: service_healthy -
Add a startup wait in CI if healthchecks are unavailable:
for i in $(seq 1 30); do mysqladmin ping -h 127.0.0.1 -u root -ppassword 2>/dev/null && break sleep 2 done -
Verify the environment variables for the connection string:
echo "HOST=$DB_HOST PORT=$DB_PORT USER=$DB_USER"
Validation
mysqladmin ping -h <host> -P 3306 -u root -p<password>exits zero.mysql -h <host> -u root -p<password> -e "SELECT 1"succeeds.- Re-run the failing test step.
Why it matters
MySQL is one of the most common database engines in CI test suites. A race condition between the MySQL service startup and the application’s first connection attempt causes every test to fail with a connection error. The error message is unambiguous but the fix — adding healthcheck dependencies or a startup wait — is easy to overlook when setting up a service from scratch.
Prevention
- Always include a healthcheck in MySQL service definitions and depend on
service_healthy, notservice_started. - Use
mysqladmin pingas the health probe — it confirms the daemon is ready to accept connections, not just that the process is running.
Try it locally
mysqladmin ping -h 127.0.0.1 -P 3306 -u root -ppassword
mysql -h 127.0.0.1 -u root -ppassword -e "SELECT 1"
mysqladmin ping -h 127.0.0.1 -P 3306 -u root -ppassword
How Faultline detects it
Use faultline explain mysql-connection-refused to see the full playbook.
faultline analyze build.log
faultline explain mysql-connection-refused
Generated from playbooks/bundled/log/deploy/mysql-connection-refused.yaml. Do not edit directly.