First, make sure that parallel-ssh is installed.


When using the paramiko based clients, parallel-ssh makes use of gevent’s monkey patching to enable asynchronous use of the Python standard library’s network I/O as paramiko does not and cannot natively support non-blocking mode.

Monkey patching is only done for the clients under pssh.clients.miko and the deprecated imports pssh.pssh_client and pssh.ssh_client.

Make sure that these imports come before any other imports in your code in this case. Otherwise, patching may not be done before the standard library is loaded which will then cause the (g)event loop to be blocked.

If you are seeing messages like This operation would block forever, this is the cause.

Native clients under pssh.clients.native do not perform monkey patching and are an option if monkey patching is not suitable. These clients will become the default, replacing the current pssh.pssh_client, in a future major release - 2.0.0.

Run a command on hosts in parallel

The most basic usage of parallel-ssh is, unsurprisingly, to run a command on multiple hosts in parallel.

Examples in this documentation will be using print as a function, for which a future import is needed in Python 2.7 and below.

Make a list or other iterable of the hosts to run on:

from __future__ import print_function
from pssh.clients import ParallelSSHClient

hosts = ['host1', 'host2', 'host3', 'host4']

Where host1 to host4 are valid host names. IP addresses may also be used.

Create a client for these hosts:

client = ParallelSSHClient(hosts)

The client object can, and should, be reused. Existing connections to hosts will remain alive as long as the client object is kept alive. Subsequent commands to the same host(s) will reuse their existing connection and benefit from much faster response times.

Now one or more commands can be run via the client:

output = client.run_command('whoami')

When the call to run_command returns, the commands are already executing in parallel.

Output is keyed by host name and contains a host output object. From that, SSH output is available.


Multiple identical hosts will have their output key de-duplicated so that their output is not lost. The real host name used is available as host_output.host where host_output is a pssh.output.HostOutput object.

Standard Output

Standard output, aka stdout for host1:

for line in output['host1'].stdout:
<your username here>

There is nothing special needed to ensure output is available.

Please note that retrieving all of a command’s standard output by definition requires that the command has completed.

Iterating over stdout for any host to completion will therefor only complete when that host’s command has completed unless interrupted.

The timeout keyword argument to run_command may be used to cause output generators to timeout if no output is received after the given number of seconds - see join and output timeouts (native clients only).

stdout is a generator. Iterating over it will consume the remote standard output stream via the network as it becomes available. To retrieve all of stdout can wrap it with list, per below.

stdout = list(output['host1'].stdout)


This will store the entirety of stdout into memory and may exhaust available memory if command output is large enough.

All hosts iteration

Of course, iterating over all hosts can also be done the same way.

for host, host_output in output.items():
    for line in host_output.stdout:
        print("Host [%s] - %s" % (host, line))

Exit codes

Exit codes are available on the host output object.

First, ensure that all commands have finished and exit codes gathered by joining on the output object, then iterate over all host’s output to print their exit codes.

for host, host_output in output.items():
    print("Host %s exit code: %s" % (host, host_output.exit_code))

See also

Host output class documentation.


By default parallel-ssh will use an available SSH agent’s credentials to login to hosts via public key authentication.

User/Password authentication

User/password authentication can be used by providing user name and password credentials:

client = ParallelSSHClient(hosts, user='my_user', password='my_pass')


On Posix platforms, user name defaults to the current user if not provided.

On Windows, user name is required.

Programmatic Private Key authentication

It is also possible to programmatically provide a private key for authentication.

Native Client

For the native client - pssh.clients.ParallelSSHClient - only private key filepath is needed. The corresponding public key must be available in the same directory as my_pkey.pub where private key file is my_pkey. Public key file name and path will be made configurable in a future version.

from pssh.clients import ParallelSSHClient

client = ParallelSSHClient(hosts, pkey='my_pkey')

Paramiko Client

For the paramiko based client only, the helper function load_private_key is provided to easily load all possible key types. It takes either a file path or a file-like object.

File path:
from pssh.clients.miko import ParallelSSHClient
from pssh.utils import load_private_key

pkey = load_private_key('my_pkey.pem')
client = ParallelSSHClient(hosts, pkey=pkey)


The two available clients support different key types and authentication mechanisms - see Paramiko and libssh2 documentation for details, as well as clients features comparison.

Output for Last Executed Commands

Output for last executed commands can be retrieved by get_last_output:

output = client.get_last_output()
for host, host_output in output.items():
    for line in host.stdout:

This function can also be used to retrieve output for previously executed commands in the case where output object was not stored or is no longer available.

New in 1.2.0

Retrieving Last Executed Commands

Commands last executed by run_command can also be retrieved from the cmds attribute of ParallelSSHClient:

output = {}
for i, host in enumerate(hosts):
    cmd = self.cmds[i]
    client.get_output(cmd, output)
    print("Got output for host %s from cmd %s" % (host, cmd))

New in 1.2.0

Host Logger

There is a built in host logger that can be enabled to automatically log output from remote hosts. This requires the consume_output flag to be enabled on join.

The helper function pssh.utils.enable_host_logger will enable host logging to standard output, for example:

from pssh.utils import enable_host_logger

output = client.run_command('uname')
client.join(output, consume_output=True)
[localhost]       Linux

Using standard input

Along with standard output and error, input is also available on the host output object. It can be used to send input to the remote host where required, for example password prompts or any other prompt requiring user input.

The stdin attribute is a file-like object giving access to the remote stdin channel that can be written to:

output = client.run_command('read')
stdin = output['localhost'].stdin
stdin.write("writing to stdin\\n")
for line in output['localhost'].stdout:
writing to stdin

Errors and Exceptions

By default, parallel-ssh will fail early on any errors connecting to hosts, whether that be connection errors such as DNS resolution failure or unreachable host, SSH authentication failures or any other errors.

Alternatively, the stop_on_errors flag is provided to tell the client to go ahead and attempt the command(s) anyway and return output for all hosts, including the exception on any hosts that failed:

output = client.run_command('whoami', stop_on_errors=False)

With this flag, the exception output attribute will contain the exception on any failed hosts, or None:

for host, host_output in output.items():
    print("Host %s: exit code %s, exception %s" % (
          host, host_output.exit_code, host_output.exception))
host1: 0, None
host2: None, AuthenticationException <..>

See also

Exceptions raised by the library can be found in the pssh.exceptions module.