> ## Documentation Index
> Fetch the complete documentation index at: https://rydantic.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# PostgreSQL and MySQL

> Use independent SQL drivers and native database representations.

Enable either driver or both:

```toml theme={"system"}
rydantic = { version = "=0.7.0", features = ["axum", "postgres", "mysql"] }
```

Keep the same `User` model and CRUD calls. The pool or transaction type selects the driver:

```rust theme={"system"}
use rydantic::sqlx::{postgres::PgPoolOptions, mysql::MySqlPoolOptions};

let postgres = PgPoolOptions::new()
    .connect(&std::env::var("POSTGRES_URL")?).await?;
let mysql = MySqlPoolOptions::new()
    .connect(&std::env::var("MYSQL_URL")?).await?;

User::migrate(&postgres).await?;
User::migrate(&mysql).await?;
let user = User::parse_json(r#"{"name":" Alice ","age":25}"#)?;
let pg_user = user.insert(&postgres).await?;
let my_user = user.insert(&mysql).await?;
assert!(User::get(&postgres, &pg_user.id.unwrap()).await?.is_some());
assert!(User::get(&mysql, &my_user.id.unwrap()).await?.is_some());
let users = User::select().limit(20).fetch_all(&postgres).await?;
```

| Backend | Feature | SQLx pool | Generated key |
| - | - | - | - |
| SQLite | `sqlite` | `SqlitePool` | INTEGER PRIMARY KEY AUTOINCREMENT |
| PostgreSQL | `postgres` | `PgPool` | BIGINT GENERATED BY DEFAULT AS IDENTITY |
| MySQL 8 | `mysql` | `MySqlPool` | BIGINT AUTO\_INCREMENT |

Each enabled driver gets a validated SQLx `FromRow` implementation. The adapter uses native parameter binding, identifier quoting and pagination syntax. PostgreSQL and SQLite return written rows with `RETURNING`. MySQL reads the stored row by its key on the same transaction and connection, then validates it before committing; unchanged updates still return the existing row. Omitted keys use the returned insert ID. Explicit zero keys follow MySQL's SQL mode, and the returned model contains the stored key.

Use `User::create_table_sql::<rydantic::sqlx::Postgres>()` and `User::create_index_sql::<rydantic::sqlx::Postgres>()` to preview DDL. Select `Sqlite` or `MySql` as the type parameter for another driver. Schema creation and CRUD reject overlong server identifiers before executing SQL. Generated server index and foreign-key names fit identifier limits.

MySQL creates InnoDB tables with `utf8mb4_0900_bin` collation and inline indexes/foreign keys. Unbounded text/binary fields use LONGTEXT/LONGBLOB. Keys, unique/indexed fields and references use VARCHAR/VARBINARY: `#[sql(length = N)]` overrides the model's `max_length`, with a default of 191 when neither is set. Writes check those bounds before executing SQL and report `sql_length` with a field path. Select bounds that fit the server's row/index limits, and use compatible definitions for referenced columns.

MySQL `create_table` requires a pool and rejects borrowed connections or transactions with `sql_ddl_connection`, preserving caller-owned transactions from DDL's implicit commits. Its indexes are included when creating a new table, so `create_index_sql::<MySql>()` returns an empty list. Use `migrate` to upgrade existing tables from model definitions. PostgreSQL and SQLite schema creation can participate in caller-owned transactions.

Configure production connection options with SQLx's [PgConnectOptions](https://docs.rs/sqlx/0.9.0/sqlx/postgres/struct.PgConnectOptions.html) or [MySqlConnectOptions](https://docs.rs/sqlx/0.9.0/sqlx/mysql/struct.MySqlConnectOptions.html), including the desired TLS verification policy.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.