Gitea Database Configuration Best Practices: A Production-Ready Guide
Configure Gitea’s database via the [database] section in 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 package, which parses settings from 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 (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. 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). 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). 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 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 snippet demonstrates a secure, high-performance MySQL configuration using environment variables and Unix sockets:
[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_PASSWORDrather than hardcoding passwords inapp.ini. - Tune connection pools: Set
MaxOpenConnsto match database capacity andMaxIdleConnsto 5-10 to prevent connection churn. - Enable TLS: Configure
SSL_MODEtorequireorverify-fullto encrypt database traffic. - Control migrations: Use
AutoMigrationfor new installs, but rungitea migratemanually viacmd/migratefor controlled production upgrades. - Monitor performance: Set
SlowQueryThresholdto detect inefficient queries and adjustTimeoutfor 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 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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →