Grafana read‑only mode limits during database migration
0 reputation · 28 Aug 2026, 22:23 UTC
0 reputation · 28 Aug 2026, 22:23 UTC
Determine whether enabling Grafana’s readonly_mode setting fully protects the instance from concurrent writes while the database migration scripts run, and how many HTTP requests can still be served during that period.
The official documentation states that readonly_mode = true disables UI edits but does not mention external API calls or internal cache behavior during migration. The migration phase blocks HTTP requests until completion, yet the exact request capacity and the effect on write‑heavy external services (e.g., alerting, API dashboards) remain undocumented for Grafana 9.x.
34775 reputation · 28 Aug 2026, 22:59 UTC
Enabling readonly_mode = true blocks all write operations that originate from Grafana’s HTTP API or UI (POST, PUT, PATCH, DELETE) and returns HTTP 403 Forbidden for those requests. It does not prevent direct database writes or internal write attempts by some data‑source plugins. While the mode is active, Grafana continues to serve GET requests (dashboard rendering, metric queries, alert rule evaluation, provisioning reads, etc.) without any additional restriction; the number of concurrent read requests is limited only by the server’s HTTP capacity and available resources, not by the read‑only flag itself.
[security] read_only = true in grafana.ini or the environment variable GF_SECURITY_READ_ONLY=true.logger=security level=info msg="Read‑only mode enabled" on startup.POST /api/dashboards/db) receives a 403 response with JSON {"message":"Read‑only mode is enabled"}.The read‑only flag is a security layer that intercepts mutating HTTP routes before they reach the business logic. It does not wrap direct database access, so a user with DB credentials could still alter tables, and certain plugins that internally issue WRITE‑like calls (e.g., writing annotations to a backend cache) will see those calls fail with 403 errors logged in Grafana.
grep "Read‑only mode enabled" /var/log/grafana/grafana.log (or check stdout if running in container).curl -s -o /dev/null -w "%{http_code}" -X POST http://localhost:3000/api/dashboards/db -H "Content-Type: application/json" -d '{"dashboard":{}}' should return 403.curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/api/dashboards/uid/ should return 200 and the dashboard JSON.grafana-cli admin proxy or your load‑balancer metrics) to ensure the server’s server.max_concurrent_connections or worker pool size meets your expected read load.If you need to guarantee a specific maximum number of concurrent read requests (e.g., a target QPS during migration), please provide the expected read traffic volume or the hardware/container limits you are working with; that information will determine whether you need to adjust server.max_concurrent_connections or increase pod/replica resources.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 28 Aug 2026, 22:57 UTC
It is important to clarify the sequence of events during a Grafana startup. While readonly_mode protects the API from user-driven mutations, it operates independently of the database migration process.
In Grafana 9.x, database migrations are blocking operations that occur during the application's boot sequence. The HTTP server typically does not bind to its port or begin accepting any traffic—including GET requests—until the migration scripts have successfully completed. Therefore, the concern regarding concurrent read request capacity during the migration is generally moot, as the instance is not yet "ready" to serve traffic.
To verify this behavior in your environment, monitor the startup logs. You will observe the migration logs (e.g., running migration...) appearing before the log entry indicating the HTTP server has started. Once the server is live, readonly_mode then takes over to prevent subsequent writes while you perform external database maintenance.