Session Isolation
Every request gets an isolated database connection.
Each request runs queries against an isolated database connection acquired from a per-driver connection pool. Connections are sandboxed from other sessions and dangerous SQL statements are blocked before execution.
User A ──→ Connection from pool (permission-filtered, sandboxed)
User B ──→ Connection from pool (permission-filtered, sandboxed)
User C ──→ Connection from pool (permission-filtered, sandboxed)How It Works
When a user makes a /data request, the engine acquires a database connection from the appropriate pool (Postgres, MySQL, or SQLite). The permission-filtered SQL is executed against this connection. After the query completes, the connection is returned to the pool for reuse.
What Is Blocked
The engine validates and rewrites all incoming SQL before execution. Dangerous operations are rejected at the permission layer:
| Blocked Category | Examples |
|---|---|
| Schema modification | CREATE TABLE, DROP TABLE, ALTER TABLE |
| Filesystem access | COPY TO, pg_read_file(), LOAD_FILE() |
| System functions | current_setting(), pg_sleep(), system catalogs |
| Raw SQL execution | Only parameterized SQL from Drizzle Proxy is accepted |
| Unauthorized tables | Any table not covered by a permission is inaccessible |
All data access goes through the engine's permission layer, which validates and modifies the parameterized SQL received from the Drizzle Proxy client. Users cannot bypass permission filters or access unauthorized tables.
Connection Pooling
Each database driver maintains its own connection pool to minimize latency:
const engine = createEngine({
connections: {
main: process.env.PG_URL!, // postgres pool
warehouse: process.env.MYSQL_URL!, // mysql pool
local: './data/app.db', // sqlite (single connection)
},
limits: {
queryTimeout: 30_000, // kill slow queries (ms)
},
})- Each incoming request acquires a connection from the relevant pool
- After the query completes, the connection is returned to the pool
- If all connections are busy, new requests wait until one is available
Resource Limits
Each request is constrained to prevent a single user from consuming all server resources:
- Time --
queryTimeout(default 30 seconds) applies to every query. Exceeded queries return408 Request Timeout. - Rate --
rateLimitPerUserandrateLimitPerIPcap request frequency per minute. - Complexity --
maxRows,maxRelationDepth, andmaxFilterNestingcap query complexity.
const engine = createEngine({
limits: {
queryTimeout: 30_000, // kill slow queries (ms)
rateLimitPerUser: 200, // req/min per user
rateLimitPerIP: 500, // req/min per IP
maxRows: 10_000, // max rows a query can return
},
})Request Lifecycle
1. Request arrives with JWT
2. JWT validated → user identity extracted
3. Permissions evaluated → SQL validated and filtered
4. Connection acquired from pool
5. Permission-filtered SQL executed against the database
6. Results returned to client
7. Connection returned to poolConnections do not persist any user state between requests. Each query starts from a clean slate with the permission-filtered SQL.