Pure-TypeScript MySQL / MariaDB wire-protocol driver. Runs on Node.js and Bun, and ahead-of-time compiles to a native binary via Perry (LLVM). Zero native dependencies.
Sibling package of @perryts/postgres.
v0.1 — all milestones shipped:
- M1: Packet framing (3-byte length + seq id, >16 MB chains) + lenenc codecs
- M2: HandshakeV10 + HandshakeResponse41 +
COM_QUERY - M3: Auth plugins (
mysql_native_password,caching_sha2_password,sha256_password,mysql_clear_password, MariaDBclient_ed25519) + mid-handshake auth-switch - M4: Prepared protocol:
COM_STMT_PREPARE/EXECUTE/CLOSE+ per-connection prepared cache + binary-resultset decoder - M5: Rich type codecs —
Decimal,MyDate/MyTime/MyDateTime, 23 built-ins +registerType()extension point - M6: TLS (
SSLRequest+sslmode),Pool,Connection.cancel()viaKILL QUERY,sql\`template,parseConnectionString,resolveConnectOptions` - M7: Multi-resultset (
resultSetsonQueryResult), LOCAL_INFILE refusal by default, benchmark harness, smoke examples
import { connect } from '@perryts/mysql';
const conn = await connect({
host: '127.0.0.1',
port: 3306,
user: 'root',
password: 'secret',
database: 'test',
});
const result = await conn.query('SELECT ? + ? AS sum', [40, 2]);
console.log(result.rows); // [ { sum: 42 } ]
await conn.close();bun run verify # typecheck + bun test + node TLS tests + build
bun test # 135 unit + integration tests against mock server
bun run test:tls:node # TLS mid-stream upgrade under Node (Bun stalls on tls.connect({socket}))
bun run test:real # docker MySQL 8 + MariaDB 11 integration matrixHeadlines from bench/RESULTS.md (MySQL 8.0.45 over WAN, 30-50 iterations, median ms per query):
| Workload | Bun + @perryts/mysql | Bun + mysql2 | Node + @perryts/mysql | Node + mysql2 | Perry AOT + @perryts/mysql |
|---|---|---|---|---|---|
SELECT 1 (text) |
96.6 | 485.8 | 84.1 | 80.5 | 67.0 |
SELECT ? AS v (prep) |
69.3 | 181.0 | 89.7 | 68.6 | 80.0 |
SELECT * LIMIT 1000 |
96.1 | 112.8 | 113.9 | 99.2 | 122.5 |
SELECT * LIMIT 10000 |
330.4 | 457.9 | 567.8 | 475.9 | — |
- 5-7× faster than
mysql2under Bun on small queries (mysql2's warm-up under Bun is sub-optimal; this driver doesn't have that cliff). - Comparable to
mysql2under Node at the median across all workloads — within 20% on every row. - Perry AOT wins
SELECT 1outright at 32 ms min, brushing the WAN floor of ~30 ms. - Best median on 10k-row results under Bun (330 ms vs
mysql2's 458 ms), though Bun has a long p95 tail driven by GC on large row objects — see notes inbench/RESULTS.md.
(cd bench && bun install) # pulls mysql2 / mysql into bench/node_modules only
MYSQL_HOST=127.0.0.1 MYSQL_TCP_PORT=33306 MYSQL_USER=... \
bash bench/run-all.sh # runs @perryts/mysql, mysql2, mysql legacy side by side- No
pg-style OIDs: MySQL identifies types via a singleMYSQL_TYPE_*byte + a 2-byte flag field. Codecs key on those. - Binary protocol for parameterised queries, text protocol for parameter-less.
- Rows returned as
{ fields, rows, rowsArray, rowsRaw, command, rowCount }(raw bytes for GUI consumers + decoded objects for ergonomics). - Zero dependencies at runtime.
mysql2/mysqlare dev-only (bench only).
MIT.