# Gitea Database Configuration Best Practices: A Production-Ready Guide

> Optimize Gitea database configuration for production. Learn best practices for SQLite PostgreSQL MySQL connection pooling and TLS security in app ini settings.

- Repository: [Gitea/gitea](https://github.com/go-gitea/gitea)
- Tags: best-practices
- Published: 2026-03-07

---

**Configure Gitea’s database via the `[database]` section in [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini) or environment variables, choosing SQLite for single-node deployments or PostgreSQL/MySQL for production, while tuning connection pools and enabling TLS for security.**

Gitea database configuration determines the performance, reliability, and security of your self-hosted Git service. The `go-gitea/gitea` repository stores all persistent data in a relational database controlled by the [`modules/setting/database.go`](https://github.com/go-gitea/gitea/blob/main/modules/setting/database.go) package, which parses settings from [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini) or equivalent environment variables. Understanding the available drivers and connection parameters ensures your deployment can handle repository traffic without connection bottlenecks or schema conflicts.

## Choose the Right Database Engine

The `SupportedDatabaseTypes` slice in [`modules/setting/database.go`](https://github.com/go-gitea/gitea/blob/main/modules/setting/database.go) (lines 18‑20) defines four supported engines. Your choice affects concurrency, backup strategies, and hardware requirements.

**SQLite3** is built-in when Gitea is compiled with the `sqlite` tag, as implemented in [`modules/setting/database_sqlite.go`](https://github.com/go-gitea/gitea/blob/main/modules/setting/database_sqlite.go). Use it for small, single-node deployments, testing environments, or Docker containers where a file-based database simplifies operations. Set `DB_TYPE = sqlite3` and configure `Path` to store the database file on fast SSD storage separate from log directories.

**MySQL / MariaDB** (`DB_TYPE = mysql`) suits high-traffic installations with existing MySQL infrastructure or requirements for horizontal scaling. Configure Unix socket connections via the `Host` parameter for lower latency on local instances.

**PostgreSQL** (`DB_TYPE = postgres`) provides advanced features like schema isolation and strict SQL compliance. It is ideal for organizations running existing PostgreSQL clusters or requiring complex query capabilities.

**MSSQL** (`DB_TYPE = mssql`) supports Windows environments already running Microsoft SQL Server infrastructure.

## Core Configuration Settings

All database parameters are defined in the `Database` struct and loaded by the `loadDBSetting` function (lines 60‑92 of [`modules/setting/database.go`](https://github.com/go-gitea/gitea/blob/main/modules/setting/database.go)). The following table details the critical settings for production deployments:

| Setting | Purpose | Recommended Value |
|---------|---------|-------------------|
| `Type` | Engine driver (mysql, postgres, mssql, sqlite3) | Match your chosen engine. |
| `Host` | Hostname, IP, or Unix-socket path | Use `/var/run/mysqld/mysqld.sock` for local MySQL to reduce TCP overhead. |
| `Name` | Database name | Keep short and alphanumeric; avoid special characters. |
| `User` / `Passwd` | Authentication credentials | Reference environment variables like `${GITEA_DATABASE_PASSWORD}` instead of storing plaintext. |
| `Schema` | PostgreSQL schema name | Set when sharing a cluster with other applications to isolate Gitea tables. |
| `SSLMode` | TLS encryption mode | Use `require` for MySQL or `verify-full` for PostgreSQL in production environments. |
| `Path` | SQLite file location | Default is `AppDataPath/gitea.db`; ensure the path resides on a dedicated fast disk. |
| `Timeout` | SQLite busy-timeout in milliseconds | Increase to `1000` or higher for heavy write loads to prevent "database locked" errors. |
| `LogSQL` | SQL statement logging | Enable (`true`) only during debugging; disable in production to reduce I/O. |
| `MysqlCharset` / `CharsetCollation` | Character encoding | Use `utf8mb4` with `utf8mb4_bin` collation for full Unicode support and case-sensitive matching. |
| `DBConnectRetries` | Connection retry attempts | Default of `10` handles temporary network blips; increase for unreliable networks. |
| `DBConnectBackoff` | Delay between retries | Default `3s` balances recovery speed with load; increase for cloud database failover scenarios. |
| `MaxOpenConns` | Maximum open connections | Set to match your database worker processes (e.g., `50` for dedicated DB servers). |
| `MaxIdleConns` | Idle connection pool size | Maintain `5`‑`10` connections to avoid connection churn during traffic spikes. |
| `ConnMaxLifetime` | Connection maximum age | For MySQL, use a few minutes (e.g., `3s`) to handle stale connections; keep `0` for PostgreSQL. |
| `IterateBufferSize` | Rows fetched per iteration | Default `50` works for most operations; increase for bulk export jobs. |
| `AutoMigration` | Schema migration on startup | Enable (`true`) for fresh installs; disable (`false`) in production if you prefer running `gitea migrate` manually via `cmd/migrate`. |
| `SlowQueryThreshold` | Query duration warning threshold | Set to `2s` to catch inefficient queries before they impact performance. |

## Building the Connection String

Gitea constructs driver-specific Data Source Names (DSN) via the `DBConnStr()` function (lines 94‑134 of [`modules/setting/database.go`](https://github.com/go-gitea/gitea/blob/main/modules/setting/database.go)). Understanding these formats helps troubleshoot connectivity issues and integrate external monitoring tools.

For **MySQL**, the DSN follows the format `user:passwd@tcp(host)/name?parseTime=true&tls=...`.

For **PostgreSQL**, the `getPostgreSQLConnectionString()` function (lines 62‑81) builds a URL-encoded connection string handling SSL modes and schema parameters.

For **MSSQL**, the DSN uses the format `server=host; port=port; database=name; user id=user; password=passwd;`.

For **SQLite**, the string becomes `file:path?cache=shared&mode=rwc&_busy_timeout=...&_txlock=immediate`, enabling write-ahead logging and shared cache modes.

Access the final DSN programmatically by calling `setting.DBConnStr()` if developing custom Gitea extensions.

## Security Best Practices

Never commit database passwords to version control. The [`docker/root/etc/templates/app.ini`](https://github.com/go-gitea/gitea/blob/main/docker/root/etc/templates/app.ini) template demonstrates using placeholders like `${DB_PASSWD}` that Gitea expands from environment variables such as `GITEA_DATABASE_PASSWORD` or `GITEA_DATABASE_HOST`.

Enable TLS encryption by setting `SSL_MODE = require` for MySQL or `SSL_MODE = verify-full` for PostgreSQL to prevent man-in-the-middle attacks. Restrict database network access to localhost or private subnets, and configure firewall rules to block external traffic on database ports.

Create a least-privilege database user granting only `SELECT`, `INSERT`, `UPDATE`, `DELETE`, and `CREATE` permissions on the Gitea schema. Avoid using the database root account or `SUPER` privileges.

## Performance Optimization

Reduce connection overhead by increasing `MaxOpenConns` to match your database server's worker capacity and maintaining `MaxIdleConns` at 5-10 to handle traffic spikes without establishing new TCP connections.

For SQLite deployments, enable Write-Ahead Logging (WAL) by setting `SQLITE_JOURNAL_MODE = WAL` in your configuration. This allows concurrent reads during writes and eliminates "database locked" errors under heavy load. Additionally, raise the `Timeout` value above 1000ms for write-intensive operations.

During bulk import operations, temporarily increase `IterateBufferSize` to reduce database round-trips. Set `SlowQueryThreshold` to `2s` and enable `LogSQL` during testing phases to identify N+1 queries or missing indexes before production deployment.

## Handling Schema Migrations

The `AutoMigration` setting controls whether Gitea automatically applies schema changes on startup. Enable this for fresh installations to ensure tables and indexes exist. For production upgrades, set `AutoMigration = false` and manually execute `gitea migrate` (implemented in `cmd/migrate`) to control downtime and verify migrations succeed before restarting the application.

## Production Configuration Example

The following [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini) snippet demonstrates a secure, high-performance MySQL configuration using environment variables and Unix sockets:

```ini
[database]
DB_TYPE = mysql
HOST = /var/run/mysqld/mysqld.sock
NAME = gitea
USER = gitea
PASSWD = ${GITEA_DATABASE_PASSWORD}
SSL_MODE = require
CHARSET_COLLATION = utf8mb4_bin
MAX_OPEN_CONNS = 50
MAX_IDLE_CONNS = 10
CONN_MAX_LIFETIME = 3s
DB_RETRIES = 10
DB_RETRY_BACKOFF = 3s
AUTO_MIGRATION = true
SLOW_QUERY_THRESHOLD = 2s
LOG_SQL = false

```

Environment variables referenced via `${...}` syntax are expanded by Gitea's configuration loader at runtime, keeping sensitive credentials out of configuration files.

## Summary

- **Select the appropriate engine**: SQLite3 for simplicity, PostgreSQL or MySQL for production scale, and MSSQL for Windows environments.
- **Secure credentials**: Use environment variables like `GITEA_DATABASE_PASSWORD` rather than hardcoding passwords in [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini).
- **Tune connection pools**: Set `MaxOpenConns` to match database capacity and `MaxIdleConns` to 5-10 to prevent connection churn.
- **Enable TLS**: Configure `SSL_MODE` to `require` or `verify-full` to encrypt database traffic.
- **Control migrations**: Use `AutoMigration` for new installs, but run `gitea migrate` manually via `cmd/migrate` for controlled production upgrades.
- **Monitor performance**: Set `SlowQueryThreshold` to detect inefficient queries and adjust `Timeout` for SQLite WAL mode to prevent locking.

## Frequently Asked Questions

### How do I switch from SQLite to MySQL or PostgreSQL in Gitea?

Export your SQLite data using Gitea's built-in dump functionality, then update the `[database]` section in [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini) to specify `DB_TYPE = mysql` or `postgres`, providing the new `Host`, `Name`, `User`, and `Passwd` values. Import the dumped SQL into your new database before restarting Gitea. The [`modules/setting/database.go`](https://github.com/go-gitea/gitea/blob/main/modules/setting/database.go) loader will validate the new connection string via `DBConnStr()` on startup.

### What is the recommended connection pool size for a busy Gitea instance?

Set `MaxOpenConns` to match the number of database worker processes available (typically 20-50 for dedicated database servers) and `MaxIdleConns` to 5-10. This configuration, defined in the `Database` struct and loaded by `loadDBSetting`, prevents connection exhaustion while minimizing the overhead of establishing new connections during traffic spikes.

### Should I enable AutoMigration in production environments?

For initial installations, set `AutoMigration = true` to allow Gitea to create necessary tables automatically. For production upgrades, disable this setting and manually run `gitea migrate` (located in `cmd/migrate`) during maintenance windows. This approach provides control over when schema changes occur and allows you to verify database backups before applying migrations.

### How do I prevent "database locked" errors when using SQLite?

Increase the `Timeout` setting to 1000ms or higher in [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini) to allow SQLite to wait for locks to clear. Additionally, enable Write-Ahead Logging by setting `SQLITE_JOURNAL_MODE = WAL`, which permits concurrent reads during write operations and significantly reduces locking contention under heavy load.