# How Database Credentials Are URL-Encoded in the Connection String

> Learn how database credentials are URL-encoded in connection strings using urllib parse quote plus in the dify plugin tools dbquery. Secure your data now.

- Repository: [Junjie.M/dify-plugin-tools-dbquery](https://github.com/junjiem/dify-plugin-tools-dbquery)
- Tags: how-to-guide
- Published: 2026-03-05

---

**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`](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/db_query/tools/db_util.py) (and identically in [`db_query_pre_auth/tools/db_util.py`](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/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`](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/db_query/tools/db_util.py), the plugin encodes the username, password, and host individually:

```python
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:

```python
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:

```python
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:

```python
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`](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/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`](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/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`](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/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.