Hướng Dẫn Sử Dụng
How to Handle Proxy Passwords Containing Special Characters in Python Requests

Table of contents
When configuring a proxy in Python Requests, a common issue is that credentials work in other tools but fail when included in a URL. The cause may lie in how the username and password are represented, especially when they contain characters such as @, :, /, #, or %.
To handle proxy passwords containing special characters, you need to distinguish credential data from URL syntax. The solution is to apply percent encoding to each credential component before assembling the proxy address.
Why do special characters cause proxy URLs to be misinterpreted?
An authenticated proxy URL is typically represented using the structure scheme://username:password@host:port. The colon separates the username from the password, while the @ sign marks the end of the credentials section.
If a password contains characters with syntactic meaning and is inserted directly into the URL, the parser may identify component boundaries incorrectly. For example, # can introduce a fragment, while / may be interpreted as the start of a path.
Some libraries can still handle certain unencoded cases. However, you should not rely on this behavior because results may differ between parsers, library versions, or intermediary tools. Using the correct representation from the start makes configuration more consistent.
Characters to watch out for
- @ and : are directly involved in the structure of the credentials section.
- / and ?: have special meaning when identifying the path and query string.
- #: may be interpreted as the start of a fragment.
- %: introduces a percent-encoded sequence.
- Spaces and Unicode characters: need to be converted into an appropriate URL representation.
What is proxy percent encoding?
Proxy percent encoding represents characters using a percent sign followed by the hexadecimal value of the corresponding byte. For example, @ is represented as %40, # as %23, and % as %25.
In Python, the urllib.parse.quote function handles this task. For usernames and passwords in proxy URLs, pass safe='' so that slashes are not left unchanged, as they are by default.
Note: percent encoding is not encryption. Anyone who obtains the URL can recover the credentials. Therefore, a proxy URL containing credentials must be protected just like the password itself.
How to encode a proxy URL correctly in Python
Encode the username and password separately
The most important rule is to encode only the individual credential components. Do not apply quote to the entire URL, because doing so will also transform the required delimiters.
The following example uses dummy credentials for illustration:
from urllib.parse import quote
username = 'user@example'
password = 'p@ss:word/#%'
encoded_username = quote(username, safe='')
encoded_password = quote(password, safe='')
The username then becomes user%40example, and the password becomes p%40ss%3Aword%2F%23%25. Characters belonging to the credentials are no longer confused with URL delimiters.
Assemble the URL after encoding
Only after the step above should you assemble the components into a proxy URL. The following example retrieves the address and port from environment configuration:
import os
proxy_host = os.environ['PROXY_HOST']
proxy_port = os.environ['PROXY_PORT']
proxy_url = f'http://{encoded_username}:{encoded_password}@{proxy_host}:{proxy_port}'
This example assumes that PROXY_HOST is a valid hostname or IPv4 address without a scheme or credentials. If you use an IPv6 address literal, the address portion of the URL must be enclosed in square brackets.
Complete Python Requests proxy configuration
In a real application, retrieve both the username and password from a configuration source rather than hardcoding them in the source code. The following snippet builds a URL from the raw credentials and then configures a Session:
import os
import requests
from urllib.parse import quote
username = quote(os.environ['PROXY_USERNAME'], safe='')
password = quote(os.environ['PROXY_PASSWORD'], safe='')
host = os.environ['PROXY_HOST']
port = os.environ['PROXY_PORT']
proxy_url = f'http://{username}:{password}@{host}:{port}'
session = requests.Session()
session.trust_env = False
session.proxies.update({'http': proxy_url, 'https': proxy_url})
response = session.get(os.environ['TARGET_URL'], timeout=float(os.environ['REQUEST_TIMEOUT']))
response.raise_for_status()
In this configuration, REQUEST_TIMEOUT must be a valid timeout value selected by the application. TARGET_URL should point to a resource you are authorized to access to test the connection.
session.trust_env = False prevents proxy settings in the environment from affecting the test. However, this option also affects the use of information from .netrc and certain certificate settings provided through the environment. Use it only when you explicitly manage the related configuration.
Distinguish the https key from the proxy scheme
The 'https' key in the proxies dictionary specifies the proxy used for HTTPS destination URLs. It does not mean that the proxy URL must begin with https://.
If the provider offers an HTTP proxy, the same URL beginning with http:// can be used for both keys. For HTTPS destinations, the connection is typically established using the CONNECT method. Use the https:// scheme for the proxy only when the service actually supports a TLS connection to the proxy.
Common mistakes when handling special characters
Encoding the entire URL
Using quote(proxy_url, safe='') is inappropriate when proxy_url is already a complete address. It also encodes the colon and slashes in the scheme, so the result no longer preserves the correct proxy URL structure.
Leave the scheme, host, port, and delimiters unchanged. Apply quote only to the username and password before assembling the URL.
Encoding already percent-encoded data again
If the original password contains @, the encoded result is %40. Encoding this string again turns % into %25, producing %2540. The credentials sent to the proxy may no longer match the original password.
Clearly define the input to the URL-building function as raw credentials. Do not automatically decode every string containing %, because an actual password may contain the literal string %40.
Using quote_plus instead of quote
The quote_plus function is generally used for form data and query string conventions, where spaces are converted to plus signs. The credentials section of a URL should not use this convention by default.
To represent spaces explicitly in a username or password, use quote(value, safe=''). Spaces will be converted to %20.
Confusing proxy authentication with destination server authentication
The auth= parameter in Requests is typically used for authentication with the destination server, not as a direct replacement for proxy credentials in this situation. Likewise, do not arbitrarily add proxy credentials to the Authorization header sent to the website.
Including credentials in the URL is suitable for proxies using an authentication mechanism that Requests supports through this configuration, typically Basic. If the proxy requires a different mechanism, you need a corresponding authentication solution; percent encoding only addresses how the data is represented.
Troubleshooting steps when the proxy still does not work
After correcting the proxy URL encoding, check each layer instead of continuing to change the password at random:
- Check the input data: confirm that the account is still valid and that there are no unintended spaces or newline characters.
- Check the URL structure: make sure the host, port, and scheme match the provider's information.
- Check the encoding step: confirm that the raw username and password are passed through quote only when building the URL.
- Check connectivity: distinguish between DNS resolution errors, connection errors, timeouts, and authentication errors.
- Check environment configuration: determine whether HTTP_PROXY, HTTPS_PROXY, and NO_PROXY affect the request.
- Check service policies: confirm whether the proxy requires source IP registration or imposes any relevant access restrictions.
A response requesting proxy authentication is usually related to the account, password, or authentication mechanism. In contrast, certificate errors and tunnel establishment errors may be related to TLS, the scheme, or connection policies. Do not treat every Requests error as a special-character issue.
You should also avoid using verify=False to address this problem. That option disables TLS certificate verification for the relevant connection; it does not fix an incorrectly parsed URL.
Protecting credentials during logging and deployment
Do not print proxy_url to the console or include the full URL in an error-tracking system. A percent-encoded string still contains recoverable credentials. Exception messages should also be reviewed before being stored or shared.
- Store credentials in a secrets management system or an appropriate configuration mechanism.
- Log only the host, port, and test status when troubleshooting.
- Redact both the username and password in support reports.
- Rotate credentials if the complete URL has been exposed publicly.
The security of the connection to the proxy must be assessed separately. Percent encoding does not protect passwords from being read in transit; with an HTTP proxy using Basic authentication, proxy credentials are not protected by TLS on the connection to the proxy merely because the destination website uses HTTPS.
Conclusion
The way to handle proxy passwords containing special characters is to use urllib.parse.quote with safe='' for the username and password individually, and only then assemble the URL. You also need to consistently use raw input to avoid repeated encoding.
When configuring a proxy in Python Requests, also check the scheme, authentication mechanism, and effects of the environment. This approach helps distinguish URL representation errors from connection errors while reducing the risk of exposing credentials during troubleshooting.
Related articles
Ready for real proxies, not just the guide?
Buy Residential, ISP, Datacenter, or Mobile proxies — live in minutes.
View products