How Database Credentials Are URL-Encoded in the Connection String

The junjiem/dify-plugin-tools-dbquery plugin uses urllib.parse.quote_plus in the DbUtil.get_url method to percent-encode usernames, passwords, and hostnames before constructing the SQLAlchemy connection URL.

The dify-plugin-tools-dbquery repository provides secure database query capabilities for the Dify platform. When handling user-provided credentials that may contain URL-reserved characters—such as @, :, /, or spaces—the plugin must sanitize these values to prevent connection string parsing failures. This is accomplished through systematic encoding within the utility class before the final URL is assembled.

The Encoding Mechanism in DbUtil.get_url

The core implementation resides in db_query/tools/db_util.py (and identically in db_query_pre_auth/tools/db_util.py). The DbUtil class exposes the get_url method, which orchestrates the safety transformation of credential components.

Step 1: Percent-Encoding with quote_plus

Each credential component is passed through urllib.parse.quote_plus (imported as parse) to convert illegal URL characters into their percent-encoded equivalents. According to lines 54–56 in db_query/tools/db_util.py, the plugin encodes the username, password, and host individually:

parsed_username = parse.quote_plus(self.username)   # → URL‑encoded user

parsed_password = parse.quote_plus(self.password)   # → URL‑encoded password

parsed_host     = parse.quote_plus(self.host)       # → URL‑encoded host

This ensures that special characters like spaces become %20, @ becomes %40, and / becomes %2F, preventing them from being misinterpreted as URL delimiters.

Step 2: URL Construction

After encoding, the sanitized components are interpolated into the driver-specific scheme at line 57:

url = f"{self.get_driver_name()}://{parsed_username}:{parsed_password}@{parsed_host}"

The colon between username and password and the @ symbol before the host are now safe literal characters because the credential values themselves contain no unencoded reserved symbols.

Driver Mapping and Optional Components

The get_driver_name method (lines 38–48 in the same file) maps the generic db_type parameter to SQLAlchemy-compatible driver strings. Port numbers, database names, and additional query parameters are appended after the host segment, though these numeric and path components typically do not require the same encoding treatment as credentials.

Practical Code Examples

PostgreSQL with Special Characters

The following example demonstrates encoding of spaces, @, !, and / characters:

from db_query.tools.db_util import DbUtil

db = DbUtil(
    db_type="postgresql",
    username="my user",          # contains a space

    password="pa@ss!",           # contains @ and !

    host="my/host",              # contains a slash

    port="5432",
    database="mydb"
)

print(db.get_url())

# Output:

# postgresql+psycopg2://my%20user:pa%40ss%21@my%2Fhost:5432/mydb

MySQL with Colons and Slashes

This example shows how : and / within passwords are handled:

db_mysql = DbUtil(
    db_type="mysql",
    username="root",
    password="p@ss:w/ord",       # colon and slash need encoding

    host="127.0.0.1",
    port="3306",
    database="testdb"
)

print(db_mysql.get_url())

# Output:

# mysql+pymysql://root:p%40ss%3Aw%2Ford@127.0.0.1:3306/testdb

Summary

  • The DbUtil.get_url method in db_query/tools/db_util.py handles all credential encoding for the plugin
  • urllib.parse.quote_plus percent-encodes the username, password, and host before URL assembly
  • This prevents authentication failures caused by URL-reserved characters like @, :, /, and whitespace
  • The driver name mapping (lines 38–48) ensures the encoded credentials are wrapped in the correct SQLAlchemy protocol scheme
  • Both the standard db_query and db_query_pre_auth variants implement identical encoding logic for consistency

Frequently Asked Questions

Why does the plugin use quote_plus instead of quote?

quote_plus encodes spaces as plus signs (+) rather than %20, following the application/x-www-form-urlencoded standard. While SQLAlchemy accepts both encodings, quote_plus ensures broader compatibility with database drivers that expect traditional form encoding for credential components, particularly in connection string query parameters.

Which specific fields get URL-encoded in the connection string?

According to the source code at lines 54–56 of db_query/tools/db_util.py, the plugin explicitly encodes three fields: self.username, self.password, and self.host. The port number and database name are appended without additional encoding, as they occupy positions in the URL structure where reserved characters are less likely to cause parsing ambiguity.

What happens if my password contains a percent sign?

A literal % character in your password is encoded as %25 by quote_plus. This double-encoding ensures that SQLAlchemy's URL parser interprets the original percent sign as data rather than the beginning of an escape sequence, preventing authentication errors when connecting with passwords containing percent symbols.

Where is the driver name mapping defined?

The get_driver_name method between lines 38–48 in db_query/tools/db_util.py provides the translation logic. It maps generic database types (e.g., "postgresql", "mysql") to specific driver strings (e.g., "postgresql+psycopg2", "mysql+pymysql"), ensuring the encoded credentials are injected into a valid SQLAlchemy-compatible connection scheme.

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 →