Henrietta Martingale
Henrietta Martingale

Reputation: 891

How do I use SQLAlchemy create_engine() with password that includes an @

This works:

db = pyodbc.connect('driver={SQL Server Native Client 11.0}; server=172.30.0.194; database=db;uid=someuser; pwd=fancy@password')

This doesn't

cn_string = "mssql+pyodbc://someuser:"fancy&password"@172.30.0.194/db?driver=SQL+Server+Native+Client+11.0"
return create_engine(cn_string)

This doesn't either:

driver = "SQL Server Native Client 11.0"
server = "192.30.0.194"
database = "EPM_Dashboard"
uid = "someuser"
pwd = "fancy@password"
params = f'DRIVER={{{driver}}};SERVER={server};DATABASE={database};UID={uid};PWD={{{pwd}}};'

connection_string = 'mssql+pyodbc:///?odbc_connect=%s' % urllib.parse.quote_plus(params)

return create_engine(connection_string)

I get something like:

Login timeout expired (0); [08001] [Microsoft][SQL Server Native Client 11.0]A network-related or instance-specific error has occurred while establishing a connection to SQL Server. Server is not found or not accessible. Check if instance name is correct and if SQL Server is configured to allow remote connections. For more information see SQL Server Books Online. (53)

which would be more believable if the pyodbc item failed.

Here's another failure:

return create_engine(urllib.parse.quote_plus('driver={SQL Server Native Client 11.0}; server=172.30.0.194; database=EPM_Dashboard;uid=someuser; pwd=fancy@password'))
    

I'm sure there's a tricky character somewhere I'm missing.

Here are some resources

https://github.com/mkleehammer/pyodbc/wiki/Connecting-to-databases

Special character in SQL password

SqlAlchemy equivalent of pyodbc connect string using FreeTDS

Upvotes: 6

Views: 11517

Answers (1)

Gord Thompson
Gord Thompson

Reputation: 123729

If you need to construct a connection URL that may have "funny characters" in it then you can use URL.create() to build it for you:

import sqlalchemy as sa

connection_url = sa.URL.create(
    "mssql+pyodbc",
    username="someuser",
    password="fancy@password",
    host="192.30.0.194",
    database="EPM_Dashboard",
    query={"driver": "SQL Server Native Client 11.0"},
)
engine = sa.create_engine(connection_url)

For those who are curious, the stringified version of the URL is

print(connection_url.render_as_string(hide_password=False))
# mssql+pyodbc://someuser:fancy%[email protected]/EPM_Dashboard?driver=SQL+Server+Native+Client+11.0

but note that it is NOT necessary to convert the URL object to string before passing it to create_engine().

Upvotes: 16

Related Questions