Does MySQL Work With Cloudflare Pages?
You can use MySQL with Cloudflare Pages, but only through serverless functions or external APIs since Pages itself doesn't run traditional backend servers.
Quick Facts
How MySQL Works With Cloudflare Pages
Cloudflare Pages is a static site hosting and edge computing platform designed for JAMstack deployments. It doesn't provide direct MySQL integration or long-running server processes. However, you can connect to MySQL databases through Cloudflare Workers (which power Pages Functions) using connection pooling libraries or by routing requests to an external API.
The typical architecture involves creating serverless functions deployed with your Pages site that handle database queries. You'll connect to MySQL via libraries like `mysql2/promise` or `prisma` through Cloudflare's network. The key consideration is connection management—MySQL connections are stateful and expensive, so you must use connection pools rather than creating new connections per request. Many developers use Prisma with its Data Proxy or deploy a separate serverless function layer (like Vercel Functions or AWS Lambda) as an intermediate API that your Pages frontend calls.
For production applications, the recommended pattern is to treat MySQL as a separate backend service and communicate with it via REST/GraphQL APIs rather than direct connections from Pages Functions. This provides better security, connection pooling, and doesn't expose database credentials to edge locations worldwide.
Best Use Cases
Quick Setup
npm install mysql2/promise// functions/api/users.ts - Cloudflare Pages Function
import { createPool } from 'mysql2/promise';
export const onRequest = async (context) => {
const pool = createPool({
host: context.env.DB_HOST,
user: context.env.DB_USER,
password: context.env.DB_PASSWORD,
database: context.env.DB_NAME,
waitForConnections: true,
connectionLimit: 5,
queueLimit: 0,
});
try {
const connection = await pool.getConnection();
const [rows] = await connection.query('SELECT id, name FROM users LIMIT 10');
connection.release();
return new Response(JSON.stringify(rows), {
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
return new Response('Database error', { status: 500 });
} finally {
await pool.end();
}
};Known Issues & Gotchas
MySQL connection pooling is critical—creating new connections per request will exhaust connection limits and cause timeouts
Fix: Use Prisma Data Proxy, PlanetScale's serverless MySQL, or implement connection pooling with pg (if using PostgreSQL alternatives). Cloudflare Workers have limits on concurrent connections.
Cold starts and connection establishment add latency for database queries executed at the edge
Fix: Cache query results aggressively using Cloudflare's caching layer, or pre-generate static content at build time. Keep database operations minimal in hot paths.
Database credentials and connection strings are exposed in edge function code, creating security risks
Fix: Use Cloudflare Secrets/Environment Variables and restrict database access by IP. Consider a separate API gateway layer instead of direct MySQL connections.
Pages Functions have execution time limits (50ms for free tier, up to 30s for Workers), affecting complex queries
Fix: Optimize queries, use database indexes, and consider breaking work into async tasks or background jobs for heavy operations.
Alternatives
- •PostgreSQL with PlanetScale (serverless MySQL alternative) + Cloudflare Pages—native pooling and better performance
- •Supabase (PostgreSQL backend) + Cloudflare Pages—managed database with built-in API layer
- •Firebase Realtime Database + Cloudflare Pages—fully managed NoSQL alternative with real-time sync
Resources
Related Compatibility Guides
Explore more compatibility guides