Does MySQL Work With Fly.io?

Fully CompatibleLast verified: 2026-02-26

MySQL works excellently with Fly.io through managed database services or self-hosted containers, enabling you to run full-stack applications with persistent data across Fly's global infrastructure.

Quick Facts

Compatibility
full
Setup Difficulty
Easy
Official Integration
No — community maintained
Confidence
high
Minimum Versions
MySQL: 5.7

How MySQL Works With Fly.io

Fly.io doesn't offer a managed MySQL service directly, but you have two proven patterns: use Fly Postgres (their managed offering) as an alternative, or deploy MySQL in a Docker container on Fly alongside your app. Most developers choose the container approach for MySQL compatibility—you define a Dockerfile for MySQL and deploy it as a separate Fly app, then connect from your main app using Fly's private networking. Alternatively, you can use external managed MySQL (AWS RDS, PlanetScale, DigitalOcean) and connect securely via Fly's WireGuard tunnel or standard TCP connections. The developer experience is smooth: connection strings work identically whether MySQL is co-located or remote. Network latency is negligible for most workloads since Fly's infrastructure spans globally, and you can strategically place your database app in regions closest to your primary users. For high-availability setups, containerized MySQL on Fly works but requires careful volume management—data persistence uses Fly Volumes, which are regional.

Best Use Cases

Legacy applications migrating from traditional hosting that require MySQL specifically
WordPress and PHP-based CMS deployments where MySQL is non-negotiable
Multi-region Node.js or Ruby apps needing low-latency database access via Fly's global edge
Development and staging environments where you want MySQL parity with production systems

Quick Setup: Node.js App Connecting to MySQL on Fly

bash
npm install mysql2/promise dotenv
javascript
import mysql from 'mysql2/promise';
import dotenv from 'dotenv';

dotenv.config();

const pool = mysql.createPool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  waitForConnections: true,
  connectionLimit: 5,
  queueLimit: 0
});

// Usage
const connection = await pool.getConnection();
const [rows] = await connection.query('SELECT * FROM users');
console.log(rows);
connection.release();

// In fly.toml, set env vars:
// DB_HOST = "mysql.internal" (if MySQL is another Fly app)
// DB_USER = "root"
// DB_PASSWORD = (your secret)
// DB_NAME = "myapp"

Known Issues & Gotchas

critical

MySQL container restarts lose data if no Fly Volume is attached

Fix: Always allocate a persistent volume: 'fly volumes create mysql_data --size 10' and mount it to /var/lib/mysql in your Dockerfile

warning

Single container MySQL has no automatic failover or high availability

Fix: Use managed MySQL (PlanetScale, AWS RDS) for production, or implement Fly Machines with custom health checks and manual replication setup

warning

Regional Fly Volumes can't be accessed from other regions

Fix: Keep your MySQL app and primary app in the same region, or use an external managed service with cross-region replication

warning

Connection pooling is critical—Fly apps can exhaust MySQL connections quickly under load

Fix: Use PgBouncer or implement connection pooling in your application (node-mysql2/promise, Rails ActiveRecord pooling, etc.)

Alternatives

  • PostgreSQL with Fly Postgres (native managed service, simpler operations)
  • PlanetScale (managed MySQL compatible platform, serverless, excellent Fly.io integration)
  • MongoDB Atlas with Fly.io (if you need document database instead of relational)

Resources

Related Compatibility Guides

Explore more compatibility guides