MySQL

Lightweight in-memory MySQL implementation speaking the real wire protocol.

KeyValue
Port3306
ProtocolWire protocol (TCP)
Size~90 KB
Startup< 200ms

Default Connection

mysql://parlel:parlel@parlel-bridge:3306/parlel
ParameterValue
Userparlel
Passwordparlel
Databaseparlel

Supported SQL

DDL

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  email VARCHAR(255) NOT NULL,
  name VARCHAR(255),
  age INT DEFAULT 0,
  active BOOLEAN DEFAULT true
);

ALTER TABLE users ADD COLUMN role VARCHAR(50);
ALTER TABLE users DROP COLUMN role;
CREATE INDEX idx_users_email ON users (email);
CREATE UNIQUE INDEX idx_users_email_unique ON users (email);
DROP INDEX idx_users_email ON users;
TRUNCATE TABLE users;
DROP TABLE users;

DML

INSERT INTO users (email, name) VALUES ('alice@test.com', 'Alice');
INSERT INTO users (email, name, age) VALUES ('bob@test.com', 'Bob', 30);

SELECT * FROM users;
SELECT name, email FROM users;
SELECT * FROM users WHERE id = 1;
SELECT * FROM users WHERE age > 25;
SELECT * FROM users WHERE name LIKE 'A%';
SELECT COUNT(*) FROM users;
SELECT * FROM users ORDER BY name ASC;
SELECT * FROM users LIMIT 10 OFFSET 5;
SELECT * FROM users WHERE id IN (1, 2, 3);
SELECT * FROM users WHERE age BETWEEN 20 AND 30;

UPDATE users SET name = 'Alice Updated' WHERE id = 1;
DELETE FROM users WHERE id = 1;

Introspection

SELECT 1;
SHOW TABLES;
SHOW DATABASES;
DESCRIBE users;
EXPLAIN SELECT * FROM users;

Transactions & sessions

BEGIN;                 -- or START TRANSACTION
COMMIT;
ROLLBACK;
SAVEPOINT sp1;
USE parlel;
SET autocommit = 1;

GRANT, REVOKE, CREATE USER, and ALTER USER are accepted as no-ops so ORMs and migration tools that issue them do not error.

Result, OK & error packets

The emulator returns the same three response packet types real MySQL does, so drivers (mysql2, PyMySQL) frame each statement correctly:

Usage

Add the parlel/bridge sidecar to your test compose file. It exposes MySQL at parlel-bridge:3306 and your app connects with an unmodified real driver (mysql2, PyMySQL) — no Parlel code in the app.

include:
  - path: parlel-bridge.yml          # image: parlel/bridge
services:
  app:
    build: .
    env_file: test.env
    depends_on:
      parlel-bridge: { condition: service_healthy }
PARLEL_API_KEY=pk_... docker compose -f docker-compose.test.yml up

Then connect with the real driver against the parlel-bridge hostname:

import mysql from "mysql2/promise";

const conn = await mysql.createConnection({
  host: "parlel-bridge",
  port: 3306,
  user: "parlel",
  password: "parlel",
  database: "parlel",
});

await conn.query("CREATE TABLE items (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100))");
await conn.query("INSERT INTO items (name) VALUES (?)", ["Widget"]);
const [rows] = await conn.query("SELECT * FROM items");

Access via MCP (Parlel Sandbox)

When MySQL runs inside a Parlel sandbox, drive it through the sandbox's MCP endpoint with the parlel_execute tool. Pass raw SQL as command (multiple statements may be separated by ;):

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "parlel_execute",
    "arguments": {
      "service": "mysql",
      "command": "CREATE TABLE t (id INT, name VARCHAR(50)); INSERT INTO t (id, name) VALUES (1, 'Ada'); SELECT * FROM t;"
    }
  }
}

Each statement returns { statement, fields, rows, error }.

Access via Parlel Sandbox

The parlel/bridge sidecar exposes this service at parlel-bridge:3306, tunneling the raw wire protocol as TCP over the sandbox HTTPS preview proxy via WebSocket. mysql2, PyMySQL, or any driver connects to mysql://parlel:parlel@parlel-bridge:3306/parlel unmodified — with just an API key (or localhost if you run the bridge outside Docker and publish ports). No SSH tunnel, no daytona CLI.

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatus
Wire handshake + COM_QUERY/COM_PING/COM_QUIT✅ Supported
CRUD (INSERT/SELECT/UPDATE/DELETE)✅ Supported
OK packet for writes/DDL with affected_rows + last_insert_id✅ Supported
ERR packet for unknown tables and unsupported statements✅ Supported
WHERE with numeric-aware = != < > <= >=, AND/OR✅ Supported
IN (...) / NOT IN, BETWEEN, LIKE, IS [NOT] NULL✅ Supported
ORDER BY (numeric + text, ASC/DESC), LIMIT, COUNT(*)✅ Supported
Transactions (BEGIN/COMMIT/ROLLBACK)◐ Accepted (no isolation enforcement)
Indexes / foreign keys◐ Accepted (not physically enforced — results stay correct)
Authentication◐ Accepted (any credentials; fixed local creds by design)
JOIN⟳ Roadmap — single-table queries only (errors honestly)
Aggregates other than COUNT(*) / GROUP BY⟳ Roadmap — error honestly
Server-side prepared statements (binary protocol)⟳ Roadmap
Stored procedures / triggers / views⟳ Roadmap — accepted as no-ops
<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

MYSQL_ROOT_PASSWORD=parlel
MYSQL_DATABASE=parlel
MYSQL_USER=parlel
MYSQL_PASSWORD=parlel
<!-- parlel:testenv:end -->