You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Reopen Issue #491: SSH tunneling fails using paramiko+sshtunnel #565
mssql_python.connect() hangs when connecting using an SSH Tunnel created with paramiko + sshtunnel. This same setup works fine with pymssql or pyodbc.
In issue 491, using mssql-python 1.4.0, the connection would time out after 15 seconds. Using mssql-python 1.6.0, the connection simply hangs indefinitely. The fix reported in PR 541 does not appear to have been tested for this scenario.
importsshtunnelimportmssql_pythonimportpymssqlimportpyodbc# Fill in with your credentialsssh_host= {"ssh_address_or_host": "host",
"ssh_username": "",
"ssh_password": "",
"ssh_port": 22,
"local_bind_address": ('127.0.0.1', 0),
}
sql_server= {"host": "DB_HOST_IP",
"port": 1433,
"database": "my_database",
"user": "",
"password": "",
}
tunnel=sshtunnel.open_tunnel(
(ssh_host['ssh_address_or_host'], ssh_host["ssh_port"]),
ssh_username=ssh_host["ssh_username"],
ssh_password=ssh_host["ssh_password"],
local_bind_address=ssh_host["local_bind_address"],
remote_bind_address=(sql_server['host'], sql_server['port']))
try:
tunnel.start()
### Connect with pyodbcpyodbc_conn_str= (
f"Driver={{ODBC Driver 17 for SQL Server}};"f"Server={tunnel.local_bind_host},{tunnel.local_bind_port};"f"DATABASE={sql_server['database']};"f"UID={sql_server['user']};"f"PWD={sql_server['password']};""Encrypt=no;TrustServerCertificate=yes")
conn=pyodbc.connect(pyodbc_conn_str)
curs=conn.cursor()
curs.execute("SELECT 'hello from pyodbc'")
print(curs.fetchall()) ### This works### Connect with mssql_pythonCONNECTION_STRING= (
f"Server={tunnel.local_bind_host},{tunnel.local_bind_port};"f"DATABASE={sql_server['database']};"f"UID={sql_server['user']};"f"PWD={sql_server['password']};""Encrypt=no;TrustServerCertificate=yes")
conn=mssql_python.connect(CONNECTION_STRING) ### This hangs.print(conn) ### We never get to hereres=conn.execute("SELECT 'hello from mssql_python'")
print(res.fetchall())
finally:
tunnel.stop()
Expected behavior
mssql_python.connect() should connect via the open SSH Tunnel and should not hang. All expected behavior of mssql_python should work through an SSH Tunnel that is opened by the same python interpreter.
Hello Jonathan Schuba (@jschuba). I can reproduce the issue. I am working on a fix (this time I will make sure to add a representative test, however without the SSH dependency).
Essentially there are more GIL contentions to deal with.
The fix in 1.7.1 works for ordinary queries, but still hangs for queries with parameters. The queries execute and results can be fetched. But then it hangs during teardown.
Try running any query with either qmark or named parameters.
res = conn.execute("SELECT 1 as result WHERE 1=?", (1,))
print(res.fetchall())
res = conn.execute("SELECT 1 as result WHERE 1=%(parameter)s", {"parameter": 1})
print(res.fetchall())
Piggy-backing on my example above. Here, I comment where the process hangs:
### Using mssql_python version: 1.7.1
try:
tunnel.start()
### Connect with mssql_python
CONNECTION_STRING = (
f"Server={tunnel.local_bind_host},{tunnel.local_bind_port};"
f"DATABASE={sql_server['database']};"
f"UID={sql_server['user']};"
f"PWD={sql_server['password']};"
"Encrypt=no;TrustServerCertificate=yes")
conn = mssql_python.connect(CONNECTION_STRING)
print(conn)
res = conn.execute("SELECT 1 as result WHERE 1=?", (1,))
print(res.fetchall())
res = conn.execute("SELECT 1 as result WHERE 1=%(parameter)s", {"parameter": 1})
print(res.fetchall())
print("Fetched") ## This prints
conn.close()
print("Done") ## This never prints
finally:
print("In Finally") ## This never prints
tunnel.stop()
BTW Jonathan Schuba (@jschuba) I want to give you a big thank you for reporting this issue and reopening it and pushing the bar.
I appreciate the test case recommendations as well
Your feedback and this usecase has been a big source of motivation.
I think TDS over SSH is a very good usecase considering SQL server deployments are quite high value and Bastion hosts with ssh tunnelling is a pragmatic way of dealing with network isolated SQL servers.
I use this functionality daily as a data engineer.
Right now, I only do reads over SSH Tunnels with several isolated SQL Servers. I load the data into my Data Warehouse on Azure SQL Database. As such, I have no reason to do writes over an SSH Tunnel, but I would also recommend putting in a test for that.
I'm really looking forward to using this package with polars, so I can move away from pandas+BCP for bulk loads. I also support your open issue about bulkcopy_arrow. Together, SSH Tunnelling and polars/arrow bulk loads are the killer features for me.
Activity
github-actions commentedon May 11, 2026
Hi Jonathan Schuba (@jschuba), thank you for opening this issue!
Our team will review it shortly. We aim to triage all new issues within 24-48 hours and get back to you.
If you have additional information to share, please feel free to update the issue.
Thank you for your patience!
FIX: Release GIL around blocking SQLSetConnectAttr calls (#565)
TEST: Add functional regression test for issue #565
TEST: Add functional regression test for issue #565
TEST: Add functional regression test for issue #565
saurabh500 commentedon May 12, 2026
Hello Jonathan Schuba (@jschuba). I can reproduce the issue. I am working on a fix (this time I will make sure to add a representative test, however without the SSH dependency).
Essentially there are more GIL contentions to deal with.
FIX: Release GIL around blocking SQLSetConnectAttr calls (#565)
TEST: Add functional regression test for issue #565
FIX: Release GIL around blocking SQLSetConnectAttr calls (#565) (#568)
jschuba commentedon May 20, 2026
Hello Saurabh Singh (@saurabh500) , I updated to
mssql_python version: 1.7.1.The fix in
1.7.1works for ordinary queries, but still hangs for queries with parameters. The queries execute and results can be fetched. But then it hangs during teardown.Try running any query with either qmark or named parameters.
I recommend adding the following queries to the tests in test_023_ssh_tunnel_gil_release.py
Piggy-backing on my example above. Here, I comment where the process hangs:
saurabh500 commentedon May 20, 2026
Thanks, will take a look
saurabh500 commentedon May 20, 2026
BTW Jonathan Schuba (@jschuba) I want to give you a big thank you for reporting this issue and reopening it and pushing the bar.
I appreciate the test case recommendations as well
Your feedback and this usecase has been a big source of motivation.
I think TDS over SSH is a very good usecase considering SQL server deployments are quite high value and Bastion hosts with ssh tunnelling is a pragmatic way of dealing with network isolated SQL servers.
jschuba commentedon May 20, 2026
Absolutely, Saurabh Singh (@saurabh500). Thanks for taking a look at this so quickly.
I use this functionality daily as a data engineer.
Right now, I only do reads over SSH Tunnels with several isolated SQL Servers. I load the data into my Data Warehouse on Azure SQL Database. As such, I have no reason to do writes over an SSH Tunnel, but I would also recommend putting in a test for that.
I'm really looking forward to using this package with polars, so I can move away from pandas+BCP for bulk loads. I also support your open issue about bulkcopy_arrow. Together, SSH Tunnelling and polars/arrow bulk loads are the killer features for me.
FIX: Release GIL around remaining blocking ODBC paths (#565)
FIX: Release GIL around SQLDescribeParam network round-trip (#565)
FIX: Release GIL around teardown SQLFreeHandle/SQLFreeStmt (#565) (#604)
RELEASE:1.11.0 (#672)
saurabh500 commentedon Jul 13, 2026
Jonathan Schuba (@jschuba) do you want to try the newest release 1.11.0 and see if that alleviates the problems that you had been facing ?
jschuba commentedon Jul 13, 2026
Saurabh Singh (@saurabh500) The fix in
1.11.0works for me. Thank you!saurabh500 commentedon Jul 13, 2026
Thanks for the confirmation.
In case you run into problems, please open a new issue. Appreciate your patience