transact-rs/sqlx · error
failed to parse DATABASE_URL
Error message
failed to parse DATABASE_URL
What it means
After reading DATABASE_URL, `test_context` parses it with `MySqlConnectOptions::from_str(..).expect(..)`. The panic means the string exists but is not a valid MySQL connection URL (bad scheme, malformed userinfo, unparseable options).
Source
Thrown at sqlx-mysql/src/testing/mod.rs:102
}
query.push(")").build().execute(&mut conn).await?;
let _ = conn.close().await;
Ok(Some(delete_db_names.len()))
}
async fn snapshot(_conn: &mut Self::Connection) -> Result<FixtureSnapshot<Self>, Error> {
// TODO: I want to get the testing feature out the door so this will have to wait,
// but I'm keeping the code around for now because I plan to come back to it.
todo!()
}
}
async fn test_context(args: &TestArgs) -> Result<TestContext<MySql>, Error> {
let url = dotenvy::var("DATABASE_URL").expect("DATABASE_URL must be set");
let master_opts = MySqlConnectOptions::from_str(&url).expect("failed to parse DATABASE_URL");
let pool = PoolOptions::new()
// MySql's normal connection limit is 150 plus 1 superuser connection
// We don't want to use the whole cap and there may be fuzziness here due to
// concurrently running tests anyway.
.max_connections(20)
// Immediately close master connections. Tokio's I/O streams don't like hopping runtimes.
.after_release(|_conn, _| Box::pin(async move { Ok(false) }))
.connect_lazy_with(master_opts);
let master_pool = match once_lock_try_insert_polyfill(&MASTER_POOL, pool) {
Ok(inserted) => inserted,
Err((existing, pool)) => {
// Sanity checks.
assert_eq!(
existing.connect_options().host,
pool.connect_options().host,
"DATABASE_URL changed at runtime, host differs"View on GitHub (pinned to 03af8bcc57)
Solutions
- Use a properly formed URL: `mysql://user:password@host:3306/dbname`.
- Percent-encode special characters in the password (e.g. `@` -> `%40`).
- Ensure the scheme is `mysql://`, matching the MySQL test harness.
- Print/inspect DATABASE_URL (redacting credentials) to spot truncation or quoting issues in .env.
Example fix
// before (.env) DATABASE_URL=postgres://root:pw@localhost/db // after DATABASE_URL=mysql://root:pw%40special@localhost:3306/mysql
Defensive patterns
Strategy: validation
Validate before calling
// Parse-check DATABASE_URL before tests:
let url = dotenvy::var("DATABASE_URL").expect("DATABASE_URL must be set");
assert!(url.starts_with("mysql://"), "MySQL tests need mysql:// scheme, got: {:?}", &url[..url.len().min(12)]);
let _opts = sqlx::mysql::MySqlConnectOptions::from_str(&url)
.expect("DATABASE_URL is not a valid MySQL URL"); Prevention
- Percent-encode special characters in passwords
- Match the scheme to the driver: mysql:// for MySQL tests
- Validate .env values in CI before running the suite
When it happens
Trigger: `#[sqlx::test]` with DATABASE_URL set to a non-MySQL URL (e.g. `postgres://`), an empty string, missing `mysql://` scheme, or invalid URL syntax/options query string.
Common situations: Copy-pasting a Postgres URL into a MySQL test setup; typos like `mysql:/host` or unescaped special characters (`@`, `#`, `%`) in the password; leftover placeholder `DATABASE_URL=` (empty).
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- cleanup_test() invoked outside `#[sqlx::test]`
- DATABASE_URL must be set
- failed to close setup connection
- cleanup_test() invoked outside `#[sqlx::test]`
- DATABASE_URL must be set
AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03).
Data as JSON: /api/errors/eb37a5db0cbc1a15.
Report an issue: GitHub.