Query IBM i Db2 databases over SSH — no ibm_db driver required.
The ibm_db Python driver bundles IBM's proprietary ODBC/CLI libraries, which creates licensing friction, installation headaches, and platform compatibility issues. This project takes a different approach: connect to the IBM i via SSH and use its built-in db2 command-line tool.
- Python 3.7+
- SSH access to the target IBM i system
pip install db2ssh
Drop-in replacement pattern for code that expects a PEP 249 database interface:
from db2ssh import connect
conn = connect(host="your-ibm-i.example.com", user="myuser", password="mypass")
cur = conn.cursor()
cur.execute("SELECT TABLE_NAME, TABLE_TYPE FROM QSYS2.SYSTABLES WHERE TABLE_TYPE = ? FETCH FIRST 10 ROWS ONLY", ['L'])
for row in cur.fetchall():
print(row)
conn.close()With context manager:
with connect(host="your-ibm-i.example.com", user="myuser", password="mypass") as conn:
cur = conn.cursor()
cur.execute("SELECT COUNT(*) FROM QSYS2.SYSTABLES")
print(cur.fetchone())With SSH key:
conn = connect(host="your-ibm-i.example.com", user="myuser", key_filename="~/.ssh/id_rsa")Without password or key, paramiko will try SSH agent and default keys (~/.ssh/id_rsa, etc.):
conn = connect(host="your-ibm-i.example.com", user="myuser")After pip install db2ssh, the db2ssh command is available:
# Password auth
db2ssh --host your-ibm-i.example.com --user myuser --password mypass \
--query "SELECT * FROM QSYS2.SYSTABLES FETCH FIRST 5 ROWS ONLY"
# Key-based auth
db2ssh --host your-ibm-i.example.com --user myuser \
--key-file ~/.ssh/id_rsa \
--query "SELECT * FROM QSYS2.SYSTABLES FETCH FIRST 5 ROWS ONLY"
# From a SQL file
db2ssh --host your-ibm-i.example.com --user myuser --password mypass \
--file queries.sql
# Save output to file
db2ssh --host your-ibm-i.example.com --user myuser --password mypass \
--query "SELECT * FROM QSYS2.SYSTABLES" --output results.txt
# Password via environment variable
export DB2_PASSWORD=mypass
db2ssh --host your-ibm-i.example.com --user myuser \
--query "SELECT CURRENT_DATE FROM SYSIBM.SYSDUMMY1"- Opens an SSH connection to the IBM i using paramiko
- Writes the SQL statement to a temporary file on the remote system
- Executes the query via
qsh -c "db2 -f <file>" - Parses the fixed-width columnar output into structured results
- Cleans up the remote temp file
No software needs to be installed on the IBM i beyond its default SSH server and the built-in db2 command.
| Feature | Status |
|---|---|
connect() |
Implemented |
Connection.cursor() |
Implemented |
Cursor.execute() |
Implemented |
Cursor.executemany() |
Implemented |
Cursor.fetchone() |
Implemented |
Cursor.fetchmany() |
Implemented |
Cursor.fetchall() |
Implemented |
| Iterator protocol | Implemented |
| Context manager | Implemented |
? (qmark) parameter style |
Implemented |
| Error hierarchy | Implemented |
commit() |
No-op (IBM i autocommit) |
rollback() |
Raises NotSupportedError |
All errors from the IBM i are raised as DB-API 2.0 exceptions:
from db2ssh import connect, ProgrammingError, OperationalError
try:
conn = connect(host="bad-host", user="user", password="pass")
except OperationalError as e:
print(f"Connection failed: {e}")
try:
cur.execute("SELECT * FROM NONEXISTENT.TABLE")
except ProgrammingError as e:
print(f"Query failed: {e}")- Authentication: Supports password auth and SSH key-based auth. Key auth is recommended for production — use
--key-fileor passkey_filenametoconnect(). If no password or key is specified, paramiko will try your SSH agent and default keys (~/.ssh/id_rsa, etc.). - Passwords: Use the
DB2_PASSWORDenvironment variable or interactive prompt rather than passing passwords on the command line. - Host key verification: The default configuration auto-accepts unknown SSH host keys (
AutoAddPolicy). For production use, consider implementing strict host key checking. - Temp files: A uniquely-named SQL file (
/tmp/.db2ssh_<uuid>.sql) is written to the IBM i during each query execution and deleted immediately after. The UUID-based name prevents collision between concurrent executions and eliminates symlink-based TOCTOU attacks.
- Result sets only: DDL/DML statements that don't return rows will execute but won't report affected row counts accurately.
NULLliteral: BareSELECT NULLmay not work on some IBM i versions. UseCAST(NULL AS <type>)instead.- No transactions:
commit()is a no-op,rollback()raisesNotSupportedError. - Single-threaded: Each
Connectionobject holds one SSH session. Share across threads at the module level only (threadsafety=1). - No SSL/TLS: SSH transport is encrypted, but the db2 connection from the IBM i to its own database is local.
MIT