{"library":"asyncssh","title":"AsyncSSH","description":"AsyncSSH is an asynchronous Python library providing a client and server implementation of the SSHv2 protocol, built on top of the `asyncio` framework. It supports a wide range of features including shell, command, and subsystem channels, SFTP, SCP, port forwarding, and various authentication methods. The library is actively maintained, with a recent major version (2.x) and regular patch releases.","status":"active","version":"2.22.0","language":"en","source_language":"en","source_url":"https://github.com/ronf/asyncssh","tags":["async","ssh","networking","client","server","security","sftp","scp"],"install":[{"cmd":"pip install asyncssh","lang":"bash","label":"Basic Installation"},{"cmd":"pip install 'asyncssh[bcrypt,fido2,gssapi,ifaddr,pkcs11,pyopenssl,pywin32]'","lang":"bash","label":"Installation with all optional dependencies (e.g., on UNIX)"}],"dependencies":[{"reason":"Required for core cryptographic functions. AsyncSSH 2.0+ requires cryptography >=39.0.","package":"cryptography","optional":false},{"reason":"Optional, for OpenSSH private key encryption.","package":"bcrypt","optional":true},{"reason":"Optional, for U2F/FIDO2 security key authentication.","package":"fido2","optional":true},{"reason":"Optional, for GSSAPI key exchange and authentication (UNIX-like systems).","package":"gssapi","optional":true},{"reason":"Optional, for network interface address information.","package":"ifaddr","optional":true},{"reason":"Optional, for accessing PIV security tokens.","package":"pkcs11","optional":true},{"reason":"Optional, for X.509 certificate authentication.","package":"pyOpenSSL","optional":true},{"reason":"Optional, for Pageant agent support and GSSAPI on Windows.","package":"pywin32","optional":true}],"imports":[{"note":"Primary library import.","symbol":"asyncssh","correct":"import asyncssh"},{"note":"Required as AsyncSSH is built on asyncio.","symbol":"asyncio","correct":"import asyncio"}],"quickstart":{"code":"import asyncio\nimport asyncssh\nimport os\n\nasync def run_client():\n    host = os.environ.get('SSH_HOST', 'localhost')\n    port = int(os.environ.get('SSH_PORT', 22))\n    username = os.environ.get('SSH_USERNAME', 'testuser')\n    password = os.environ.get('SSH_PASSWORD', '') # Or use client_keys=['/path/to/id_rsa']\n\n    try:\n        # Connect to the SSH server\n        conn = await asyncssh.connect(host, port=port, username=username, password=password)\n\n        # Run a command and get the result\n        result = await conn.run('echo \"Hello from AsyncSSH!\"', check=True)\n        print(f\"Command: {result.command}\")\n        print(f\"Stdout: {result.stdout.strip()}\")\n        print(f\"Stderr: {result.stderr.strip()}\")\n        print(f\"Return code: {result.returncode}\")\n\n        # Close the connection (async with handles this implicitly if used for conn)\n        conn.close()\n\n    except (asyncssh.Error, OSError) as exc:\n        print(f'SSH connection or command failed: {exc}')\n\nif __name__ == '__main__':\n    # Note: For 'localhost' testing, you might need a local SSH server configured\n    # to accept connections for the specified username/password or client_key.\n    # Example to run:\n    # SSH_HOST=your_ssh_server SSH_USERNAME=your_user SSH_PASSWORD=your_pass python your_script.py\n    asyncio.run(run_client())\n","lang":"python","description":"This quickstart demonstrates how to establish an SSH client connection to a remote host, run a command, and print its output using `asyncssh.connect` and `conn.run`. It uses environment variables for host, port, username, and password for secure testing. For local testing, ensure an SSH server is running and configured correctly."},"warnings":[{"fix":"Upgrade Python to 3.10+ or pin AsyncSSH to a 1.x version compatible with your Python environment.","message":"AsyncSSH 2.0 and later requires Python 3.10 or newer. Users on older Python 3 versions (e.g., 3.6-3.9) must use AsyncSSH 1.x or upgrade their Python interpreter.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure `cryptography>=39.0` is installed alongside `asyncssh`. Check `cryptography` release notes for its own breaking changes if updating from a significantly older version.","message":"AsyncSSH 2.0+ mandates `cryptography` version 39.0 or higher. Upgrading `asyncssh` might require a concurrent upgrade of the `cryptography` dependency, which could have its own breaking changes if coming from a very old version.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Update error handling logic to catch the appropriate `asyncssh.Error` subclass (e.g., `ChannelListenError`) instead of checking for `None` return values.","message":"In AsyncSSH 2.x, methods such as `asyncssh.create_server`, `asyncssh.listen`, `asyncssh.listen_reverse`, and `SSHClientConnection`'s server/forwarding methods now raise an exception (e.g., `asyncssh.ChannelListenError`) on listen failures, instead of returning `None`.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Review calls to `SSHClientConfig.load` and ensure the new arguments are handled. Consider pinning `asyncssh<2.19.0` if immediate refactoring is not feasible.","message":"Starting with AsyncSSH 2.19.0, the `SSHClientConfig.load` method (and potentially related config parsing logic) gained new `canonical` and `final` arguments. Code that directly calls this method or relies on its previous signature might break.","severity":"breaking","affected_versions":">=2.19.0"},{"fix":"Adjust `SFTPServer` subclass `__init__` methods to correctly call `super().__init__(...)` with the expected arguments.","message":"Subclasses of `asyncssh.sftp.SFTPServer` that implement their own `__init__` method will need to update their signature in AsyncSSH 2.x to pass arguments through to the parent class.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure `asyncio.Lock` instances (and similar `asyncio` primitives) are created within the scope of the event loop where they will be used, or use Python 3.10+ where this issue is mitigated.","message":"Before Python 3.10, using `asyncio.Lock()` as a global variable could lead to `RuntimeError: 'asyncio.Lock' object is not bound to a distinct event loop` when `asyncio.run()` creates a new event loop. While not specific to AsyncSSH, this is a common footgun in `asyncio`-heavy applications.","severity":"gotcha","affected_versions":"<3.10 (Python)"}],"env_vars":null,"last_verified":"2026-04-05T00:00:00.000Z","next_check":"2026-07-04T00:00:00.000Z"}