Skip to content
Latchkey

Rails "Mysql2::Error" During Migrations in CI

The mysql2 adapter raised an error during migration. It covers two very different situations: failing to connect to MySQL at all, or MySQL rejecting a migration’s SQL. The message text tells you which.

What this error means

rails db:migrate fails with Mysql2::Error. A "Can't connect"/"Access denied" variant is a connection/auth problem; a "Duplicate column"/"Table exists" variant is a DDL/state problem. The two need different fixes.

Rails output
Mysql2::Error::ConnectionError: Can't connect to MySQL server on 'db' (111)
# or
Mysql2::Error: Duplicate column name 'status'

Diagnose it: connectivity, then migration state

Migration failures in CI are usually the database not being ready rather than the migration being wrong. A service container accepts TCP connections before it is ready to serve queries, so a migration started too early fails in confusing ways.

Terminal
# wait for readiness, not just for the port to open
until pg_isready -h localhost -p 5432; do sleep 1; done

# then inspect what the tool believes has been applied
<migrate-tool> status

Common causes

Cannot connect or access denied

MySQL is not ready, the host/port is wrong, or the credentials/grants are incorrect. The migration never runs because the connection or auth fails first.

DDL conflicts with current schema

A "Duplicate column", "Table already exists", or constraint error means the migration SQL clashes with the database’s actual state - often a re-run against a non-clean database.

How to fix it

For connection/auth errors, fix readiness and credentials

Wait for MySQL and confirm the host, port, user, and password match the service.

Terminal
until mysqladmin ping -h "$DB_HOST" --silent; do sleep 1; done
bin/rails db:prepare

For DDL errors, reconcile schema state

  1. Read whether the object already exists or is missing.
  2. Run migrations against a clean CI database so each DDL statement runs once.
  3. Fix the migration if it genuinely conflicts with a prior one.

Set credentials from secrets

.github/workflows/ci.yml
env:
  DATABASE_URL: mysql2://root:${{ secrets.MYSQL_PASSWORD }}@db:3306/app_test

How to prevent it

  • Gate db:migrate on a MySQL readiness check.
  • Run migrations against a fresh CI database so DDL is applied once.
  • Keep credentials in secrets and aligned with the service grants.

Frequently asked questions

What causes Rails "Mysql2::Error" during migrations in CI?
There are 2 common causes: cannot connect or access denied and ddl conflicts with current schema. MySQL is not ready, the host/port is wrong, or the credentials/grants are incorrect.
How do I fix Rails "Mysql2::Error" during migrations in CI?
There are 3 fixes depending on which cause you have: for connection/auth errors, fix readiness and credentials, for ddl errors, reconcile schema state, and set credentials from secrets. Work through them in order, since the first is the most common.
What does Rails "Mysql2::Error" during migrations in CI actually mean?
rails db:migrate fails with Mysql2::Error.
How do I stop Rails "Mysql2::Error" during migrations in CI happening again?
Gate db:migrate on a MySQL readiness check. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card