For everyone having issues with using SSHTunnelForwarder as a context manager, it's very likely you're letting that context end before using the database connection. This is how you can encapsulate both SSHTunnelForwarder and pymysql.connect in a new context manager:
(likewise for MySQLdb.connect, mysql.connector.connect or any other package following the Python Database API Specification)
from contextlib import contextmanager
import pymysql
from sshtunnel import SSHTunnelForwarder
@contextmanager
def connect():
tunnel = SSHTunnelForwarder(
("ssh_host", 9922),
ssh_password="ssh_password",
ssh_username="ssh_username",
remote_bind_address=("127.0.0.1", 3306),
)
tunnel.start()
try:
conn = pymysql.connect(
host="127.0.0.1",
user="user",
password="password",
database="database",
port=tunnel.local_bind_port,
)
try:
yield conn
finally:
conn.close()
finally:
tunnel.stop()
# ... then elsewhere you can do ...
with connect() as conn, conn.cursor() as cur:
cur.execute("SELECT VERSION()")
print(cur.fetchone())