<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: sen ki</title>
    <description>The latest articles on DEV Community by sen ki (@sen_ki_a60edcb313560a3b07).</description>
    <link>https://dev.to/sen_ki_a60edcb313560a3b07</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3842870%2F64246f4a-babf-4a1f-aa39-ff78fbe72c8c.png</url>
      <title>DEV Community: sen ki</title>
      <link>https://dev.to/sen_ki_a60edcb313560a3b07</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sen_ki_a60edcb313560a3b07"/>
    <language>en</language>
    <item>
      <title>One Platform for All Your Database Queries — Introducing dbquery</title>
      <dc:creator>sen ki</dc:creator>
      <pubDate>Wed, 25 Mar 2026 09:16:10 +0000</pubDate>
      <link>https://dev.to/sen_ki_a60edcb313560a3b07/one-platform-for-all-your-database-queries-introducing-dbquery-3gdg</link>
      <guid>https://dev.to/sen_ki_a60edcb313560a3b07/one-platform-for-all-your-database-queries-introducing-dbquery-3gdg</guid>
      <description>&lt;h1&gt;
  
  
  One Platform for All Your Database Queries — Introducing dbquery
&lt;/h1&gt;

&lt;p&gt;tag ： devops selfhosted database django&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The daily reality for ops and dev teams: Navicat open on one screen, DBeaver on another, Redis Desktop Manager somewhere else, MongoDB Compass somewhere else again — constantly switching. You want to let a QA engineer look up a production table, but you can't hand out the database password. New hires spend hours configuring client tools before they can do anything useful. dbquery solves all of this in one shot.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Is dbquery?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;dbquery&lt;/strong&gt; is a lightweight, self-hosted database query platform built with Django 4.2 + Bootstrap 5. It runs entirely in the browser — no client installation required — and supports &lt;strong&gt;MySQL, TiDB, PostgreSQL, Redis, and MongoDB&lt;/strong&gt;. It comes with a built-in role-based permission system so DBAs, developers, and QA engineers can safely share one tool.&lt;/p&gt;

&lt;p&gt;One command to deploy, up and running in 5 minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;GitHub: &lt;a href="https://github.com/kisen9102-lgtm/dbquery" rel="noopener noreferrer"&gt;https://github.com/kisen9102-lgtm/dbquery&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrgg2tiuqziytdfy1xi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrgg2tiuqziytdfy1xi8.png" alt=" " width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farw40709qorhhhqvxx78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farw40709qorhhhqvxx78.png" alt=" " width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwvls56dm93ot9ct18fz0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwvls56dm93ot9ct18fz0.png" alt=" " width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5er421yh3v33orcdssb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5er421yh3v33orcdssb9.png" alt=" " width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9869i49urq167k0lwknb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9869i49urq167k0lwknb.png" alt=" " width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8skyqydj9p66i09j341w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8skyqydj9p66i09j341w.png" alt=" " width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Core Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Cross-Instance Database Search
&lt;/h3&gt;

&lt;p&gt;Can't remember which server a database lives on? Type the database name into the search box and dbquery scans all registered instances, returning matching database names, their host instances, table counts, sizes, and types — all in one table.&lt;/p&gt;

&lt;p&gt;You can also search by IP + port to get an overview of all databases on a specific instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Online SQL Editor
&lt;/h3&gt;

&lt;p&gt;Select an instance and database, then start querying — right in the browser.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Syntax highlighting&lt;/strong&gt;: SQL mode for MySQL/TiDB/PostgreSQL; plain text mode for Redis/MongoDB — switches automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object browser&lt;/strong&gt;: left panel shows all tables (MySQL/PG) or collections (MongoDB); click to insert the name into the editor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-statement execution&lt;/strong&gt;: submit multiple statements at once; each returns its own result set&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSV export&lt;/strong&gt;: export any result set with one click&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Row limit&lt;/strong&gt;: results are automatically truncated with a warning to prevent accidental overload&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DB type indicator&lt;/strong&gt;: the current connection type (MySQL / TiDB / PostgreSQL / Redis / MongoDB) is shown in the top-left corner at all times&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Redis read-only command whitelist:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET  MGET  KEYS  SCAN  TYPE  TTL  PTTL  EXISTS  STRLEN  GETRANGE
INFO  DBSIZE  TIME  HGET  HGETALL  HMGET  HKEYS  HVALS  HLEN
LRANGE  LLEN  LINDEX  SCARD  SMEMBERS  SRANDMEMBER  SISMEMBER
ZRANGE  ZRANGEBYSCORE  ZREVRANGE  ZCARD  ZSCORE  ZRANK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;MongoDB query syntax:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count_documents&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$match&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...}},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...}}])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Instance Management
&lt;/h3&gt;

&lt;p&gt;Register, edit, and delete database instances from the management page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set instance name, IP, port, environment (dev / staging / production), and database type&lt;/li&gt;
&lt;li&gt;Redis / MongoDB support per-instance credentials (username, password, authSource); MySQL / TiDB / PostgreSQL use a shared service account&lt;/li&gt;
&lt;li&gt;Each instance has a &lt;strong&gt;Test Connection&lt;/strong&gt; button so you can verify connectivity before saving&lt;/li&gt;
&lt;li&gt;Color-coded type badges: MySQL (blue), TiDB (cyan), PostgreSQL (dark blue), Redis (red), MongoDB (green)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. User Management and Access Control
&lt;/h3&gt;

&lt;p&gt;A three-tier role system for precise access control:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Can Do&lt;/th&gt;
&lt;th&gt;Restrictions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;root&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Everything, no limits&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;admin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manage instances, users, and groups&lt;/td&gt;
&lt;td&gt;Cannot modify the root account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;query&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read-only SQL queries&lt;/td&gt;
&lt;td&gt;Can only see instances in their assigned groups; &lt;strong&gt;instance IP/port is hidden&lt;/strong&gt;; system databases are blocked; only SELECTis allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When a &lt;code&gt;query&lt;/code&gt; user opens the SQL editor, they only see the instances they've been granted access to — and they never see the IP address or port. Even if their account is compromised, an attacker cannot use it to connect directly to any database.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Group Management
&lt;/h3&gt;

&lt;p&gt;Create user groups, add instances and &lt;code&gt;query&lt;/code&gt; users to them. Groups are the core unit of access control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One instance can belong to multiple groups&lt;/li&gt;
&lt;li&gt;One user can belong to multiple groups&lt;/li&gt;
&lt;li&gt;All instances in a group are visible to all &lt;code&gt;query&lt;/code&gt; users in that group&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it easy to partition access by team or environment: the e-commerce team only sees e-commerce instances; the payments team only sees payments instances.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Multilingual UI
&lt;/h3&gt;

&lt;p&gt;The interface supports &lt;strong&gt;Chinese / English&lt;/strong&gt; with one click. The preference is saved in localStorage and restored on next visit.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Compares
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;dbquery&lt;/th&gt;
&lt;th&gt;Navicat&lt;/th&gt;
&lt;th&gt;DBeaver&lt;/th&gt;
&lt;th&gt;Archery&lt;/th&gt;
&lt;th&gt;Yearning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Docker, no client&lt;/td&gt;
&lt;td&gt;Desktop install&lt;/td&gt;
&lt;td&gt;Desktop install&lt;/td&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-user&lt;/td&gt;
&lt;td&gt;✅ Web, built-in&lt;/td&gt;
&lt;td&gt;❌ Per-person install&lt;/td&gt;
&lt;td&gt;❌ Per-person install&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TiDB&lt;/td&gt;
&lt;td&gt;✅ Native label&lt;/td&gt;
&lt;td&gt;⚠️ MySQL compat&lt;/td&gt;
&lt;td&gt;⚠️ MySQL compat&lt;/td&gt;
&lt;td&gt;⚠️ MySQL compat&lt;/td&gt;
&lt;td&gt;⚠️ MySQL compat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;✅ Multi-schema&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;✅ Read-only whitelist&lt;/td&gt;
&lt;td&gt;✅ (paid)&lt;/td&gt;
&lt;td&gt;✅ (plugin)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MongoDB&lt;/td&gt;
&lt;td&gt;✅ Read-only queries&lt;/td&gt;
&lt;td&gt;✅ (paid)&lt;/td&gt;
&lt;td&gt;✅ (plugin)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role-based access&lt;/td&gt;
&lt;td&gt;✅ 3 roles + groups&lt;/td&gt;
&lt;td&gt;❌ Local tool&lt;/td&gt;
&lt;td&gt;❌ Local tool&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hide IP/port from query users&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enforce read-only SQL&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis read-only whitelist&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object browser&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️ Limited&lt;/td&gt;
&lt;td&gt;⚠️ Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;i18n&lt;/td&gt;
&lt;td&gt;✅ CN/EN&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;CN only&lt;/td&gt;
&lt;td&gt;CN only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open source &amp;amp; free&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ ($200+/yr)&lt;/td&gt;
&lt;td&gt;✅ (community)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No frontend build step&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vs. &lt;strong&gt;Navicat / DBeaver&lt;/strong&gt;: dbquery is a web app — naturally multi-user, no per-person setup. Its built-in permission system lets you safely give developers and QA engineers database access without handing out credentials.&lt;/li&gt;
&lt;li&gt;vs. &lt;strong&gt;Archery / Yearning&lt;/strong&gt;: those are heavy SQL review and approval workflow platforms — powerful but complex to deploy. dbquery is lighter, focused on being a &lt;em&gt;safe online query tool&lt;/em&gt; without the workflow overhead. Better fit for small and mid-sized teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;dbquery's unique differentiator&lt;/strong&gt;: read-only access to &lt;strong&gt;Redis and MongoDB&lt;/strong&gt; — nearly absent from comparable open-source tools.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Docker + Docker Compose&lt;/li&gt;
&lt;li&gt;An external MySQL 8.0 instance as the platform metadata database (stores users, instance info)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Steps
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Create the metadata database&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;ops_db&lt;/span&gt; &lt;span class="nb"&gt;CHARACTER&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;utf8mb4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="s1"&gt;'ops_user'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'%'&lt;/span&gt; &lt;span class="n"&gt;IDENTIFIED&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="s1"&gt;'your-password'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;ops_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="s1"&gt;'ops_user'&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;'%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;FLUSH&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Configure environment variables&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; .env.docker.example .env
&lt;span class="c"&gt;# Edit .env with your metadata DB connection and query account credentials&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key &lt;code&gt;.env&lt;/code&gt; settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;DBS_DB_HOST&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal   # metadata DB host&lt;/span&gt;
&lt;span class="py"&gt;DBS_DB_PORT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3306&lt;/span&gt;
&lt;span class="py"&gt;DBS_DB_USER&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ops_user&lt;/span&gt;
&lt;span class="py"&gt;DBS_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your-password&lt;/span&gt;
&lt;span class="py"&gt;DBS_DB_NAME&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ops_db&lt;/span&gt;

&lt;span class="py"&gt;QUERY_DEFAULT_ACCOUNT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;dbs_admin    # account used to query MySQL/TiDB/PG instances&lt;/span&gt;
&lt;span class="py"&gt;QUERY_DEFAULT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your-dbs-admin-password&lt;/span&gt;

&lt;span class="py"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your-random-secret-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Start&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On first start, the container automatically: waits for MySQL → runs migrations → creates the superuser → starts gunicorn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Open&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Visit &lt;code&gt;http://localhost:8000&lt;/code&gt;. Default credentials: &lt;code&gt;dbsroot / Dbs@Root2026&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Usage Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario 1: Register a new TiDB instance
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log in as &lt;code&gt;admin&lt;/code&gt; or &lt;code&gt;root&lt;/code&gt;, go to Instance Management&lt;/li&gt;
&lt;li&gt;Click Add Instance, fill in: name &lt;code&gt;tidb-prod-primary&lt;/code&gt;, IP &lt;code&gt;10.0.1.100&lt;/code&gt;, port &lt;code&gt;4000&lt;/code&gt;, env &lt;code&gt;Production&lt;/code&gt;, type &lt;code&gt;TiDB&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click Test Connection to verify, then click Add&lt;/li&gt;
&lt;li&gt;The instance appears in the list with a cyan TiDB badge&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Scenario 2: Give a QA engineer read-only access
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to User Management → Add User, set role to &lt;code&gt;query&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go to Group Management → create a group "QA Team"&lt;/li&gt;
&lt;li&gt;Add the relevant instances to the group, add the user to the group&lt;/li&gt;
&lt;li&gt;The QA engineer logs in and sees only the instances in "QA Team" — no IP addresses, SELECT only&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Scenario 3: Find a database across all instances
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to Database Search&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;order&lt;/code&gt; in the search box&lt;/li&gt;
&lt;li&gt;dbquery scans all instances and returns every database whose name contains &lt;code&gt;order&lt;/code&gt;, with instance, type, table count, and size&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Scenario 4: Query Redis
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Select a Redis instance in the SQL editor&lt;/li&gt;
&lt;li&gt;Top-left shows &lt;code&gt;Redis&lt;/code&gt;; the object browser is hidden (Redis has no table structure)&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;db0&lt;/code&gt; from the database selector&lt;/li&gt;
&lt;li&gt;Enter a read-only command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   HGETALL user:1001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   SCAN 0 MATCH user:* COUNT 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Write commands (SET, DEL, etc.) are rejected immediately&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Scenario 5: Query MongoDB
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Select a MongoDB instance&lt;/li&gt;
&lt;li&gt;Top-left shows &lt;code&gt;MongoDB&lt;/code&gt;; the object browser lists collections with row counts&lt;/li&gt;
&lt;li&gt;Select a database and enter a query:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or aggregation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$sum&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}}}])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Security Design
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IP/port hidden from query users&lt;/strong&gt;: even if an account is compromised, the attacker cannot connect directly to any database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read-only enforcement&lt;/strong&gt;: the backend validates every SQL statement; anything other than SELECT returns 403&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis command whitelist&lt;/strong&gt;: only pre-defined read-only commands are allowed; SET/DEL/FLUSHDB are rejected&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB double validation&lt;/strong&gt;: query structure is checked with regex first, then &lt;code&gt;json.loads&lt;/code&gt; validates JSON — no &lt;code&gt;eval()&lt;/code&gt;, no injection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSRF protection&lt;/strong&gt;: all write operations require a CSRF token&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session authentication&lt;/strong&gt;: no JWT, no token leakage risk&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Get It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/kisen9102-lgtm/dbquery" rel="noopener noreferrer"&gt;https://github.com/kisen9102-lgtm/dbquery&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker image&lt;/strong&gt;: &lt;code&gt;docker pull ghcr.io/kisen9102-lgtm/dbquery:latest&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find it useful, a ⭐ on GitHub goes a long way. Issues and PRs welcome.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;dbquery — lightweight, secure, ready to deploy&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>devops</category>
      <category>django</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
