Database Query Plugin in Production: Best Practices for Dify Deployments

Use the pre-authenticated variant with isolated credentials, enforce least-privilege database users, and validate all SQL inputs to safely run the junjiem/dify-plugin-tools-dbquery plugin in production environments.

The junjiem/dify-plugin-tools-dbquery repository provides a powerful Dify plugin that enables LLM agents to execute SQL against MySQL, PostgreSQL, Oracle, and MSSQL databases. Deploying this database query plugin in production requires strict security controls, resource limits, and input validation to prevent credential exposure and SQL injection. The plugin architecture consists of a provider stub in db_query/provider/db_query.py, tool definitions in db_query/tools/sql_query.yaml, and a daemon entry point at db_query/main.py.

Security-First Configuration

Isolate Credentials with Pre-Authentication

Never expose database credentials to the LLM or its logs. The repository provides a pre-auth variant (db_query_pre_auth) that separates credential handling from LLM prompts entirely.

Store all secrets in a .env file based on the template at db_query/.env.example, and ensure this file remains outside version control:


# db_query/.env

DB_TYPE=mysql
DB_HOST=db.internal.company.com
DB_PORT=3306
DB_USERNAME=readonly_analytics
DB_PASSWORD=super_secret_key
DB_NAME=production_db
MAX_REQUEST_TIMEOUT=120

Keep .env in .gitignore and mount it as a Docker secret or environment file rather than baking it into images.

Enforce Least Privilege Database Access

Create a dedicated database user with read-only permissions (SELECT only) on specific tables. Avoid granting DROP, INSERT, UPDATE, or administrative rights unless the specific use case requires write operations. This limits the blast radius if the plugin is compromised or prompted maliciously.

Network Isolation and Signature Verification

Run the plugin daemon inside a private Docker network with direct access only to the target database host. Do not expose the daemon ports publicly.

When installing from a private or local repository, add FORCE_VERIFYING_SIGNATURE=false to your Dify .env to bypass marketplace signature checks, as documented in the repository FAQ.

Reliability and Performance Tuning

Configure Request Timeouts

The plugin daemon defaults to MAX_REQUEST_TIMEOUT=120 seconds as defined in db_query/main.py. Adjust this value based on your slowest acceptable query, but keep it as low as possible to prevent worker exhaustion from hanging connections.


# In db_query/main.py or your wrapper

MAX_REQUEST_TIMEOUT = 120  # seconds

Connection Management and Monitoring

Although the plugin uses simple SQLAlchemy-style connections, re-using the same daemon process reduces connection overhead. Deploy with Docker's --restart=always policy and allocate sufficient CPU/RAM.

Configure Dify's Tool Usage limits to prevent single users from flooding the database with requests. Forward daemon stdout/stderr to a log aggregation system (Loki, ELK, or CloudWatch), ensuring password masking is enabled to prevent credential leaks in logs.

SQL Injection Prevention

Validate and Sanitize Inputs

Even though the plugin executes raw SQL supplied by the LLM, you can mitigate injection risks through custom validation. Extend DbQueryProvider._validate_credentials in db_query/provider/db_query.py to implement a whitelist of allowed tables and columns, rejecting queries that reference unauthorized database objects.

If extending the plugin, use database drivers that support parameterized queries with placeholders (%s for MySQL, :param for PostgreSQL) rather than string interpolation:


# Safe approach using parameters

cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))

Enforce Output Formats

Force the output_format parameter to json rather than Markdown. JSON is easier to sanitize programmatically and reduces the risk of prompt injection through malformed result formatting.

Production Deployment Checklist

Before deploying the database query plugin in production, verify the following:

  • Environment File: Populate .env with credentials and place it in db_query/.env (never commit to Git).
  • Provider Registration: Confirm db_query/provider/db_query.yaml is present for Dify discovery.
  • Tool Schema: Verify db_query/tools/sql_query.yaml matches your supported db_type list.
  • Version Pinning: Use a specific Git tag (e.g., v0.0.11) in your Dockerfile to prevent accidental upgrades.
  • Health Checks: Implement a Docker healthcheck or custom /health endpoint to restart the daemon on failure.
  • Logging: Centralize logs with password masking rules applied.

Minimal Production Setup Example

Environment Configuration

Copy the template and configure your production values:

cp db_query/.env.example db_query/.env

# Edit db_query/.env with production credentials

Container Deployment

Create a Dockerfile that runs the daemon:

FROM python:3.11-slim

WORKDIR /app
COPY db_query/ /app/
RUN pip install --no-cache-dir -r requirements.txt

# Load environment variables (do NOT commit this file)

COPY .env /app/.env
ENV PYTHONUNBUFFERED=1

CMD ["python", "-m", "db_query.main"]

Deploy via Docker Compose with network isolation:

services:
  db_query_plugin:
    build: ./db_query
    env_file: ./db_query/.env
    restart: always
    networks:
      - dify_backend
      - database_network
    # Add Oracle 11g client volumes if needed

Dify Integration

In the Dify plugin marketplace, reference the plugin directory or upload the offline package. The tool appears as "Database Query" with the sql_query operation. When invoked, Dify sends a request payload matching the schema defined in sql_query.yaml:

{
  "tool_name": "sql_query",
  "parameters": {
    "db_type": "mysql",
    "query_sql": "SELECT COUNT(*) FROM orders WHERE created_at > NOW() - INTERVAL 1 DAY",
    "output_format": "json"
  }
}

Advanced Configuration

Offline Package Deployment

For air-gapped environments, build the offline zip package described in the README's "How to install the offline version" section. This allows deployment without internet access to the Dify marketplace.

Oracle 11g Client Setup

When connecting to Oracle 11g databases, follow the FAQ instructions to download the proprietary client libraries, mount them into the container, and adjust LD_LIBRARY_PATH accordingly.

Custom Validation Policies

Implement organization-wide SQL policies by extending the _validate_credentials method in db_query/provider/db_query.py. Add logic to deny specific keywords (e.g., DROP, DELETE) or restrict queries to specific schema patterns before execution.

Summary

  • Use the pre-auth variant (db_query_pre_auth) to keep credentials out of LLM context windows and logs.
  • Run database users with SELECT-only privileges on specific tables to minimize security risks.
  • Set MAX_REQUEST_TIMEOUT in db_query/main.py to prevent worker hangs, and monitor daemon logs centrally.
  • Validate SQL inputs through custom logic in DbQueryProvider and enforce JSON output formats for safer downstream processing.
  • Deploy via Docker with .env files, restart policies, and private networks, pinning to specific Git tags for reproducibility.

Frequently Asked Questions

How do I prevent the LLM from seeing my database passwords?

Use the pre-authenticated variant located in the db_query_pre_auth directory. This version stores credentials in environment variables or configuration files that the LLM never accesses, unlike the standard variant where parameters might appear in prompts. Reference db_query_pre_auth/README.md for implementation details.

The default MAX_REQUEST_TIMEOUT is 120 seconds as set in db_query/main.py. For production, set this to the 95th percentile of your query execution times plus a small buffer. Never set it to unlimited, as this can exhaust Dify's worker pool during database outages.

Can I restrict which SQL commands the plugin executes?

Yes, though it requires customization. Extend the _validate_credentials method in db_query/provider/db_query.py to parse incoming SQL and reject queries containing forbidden keywords (like DROP, DELETE, or UPDATE) or tables outside an allowed whitelist. The repository provides a stub for this validation logic.

How do I install this plugin without internet access?

Build the offline package following the repository README instructions. This creates a self-contained zip file that you can upload directly to Dify's plugin system without requiring external downloads, making it suitable for private data centers or secured environments.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →