96

Recently, I made a code that connect to work station with different usernames (thanks to a private key) based on paramiko.

I never had any issues with it, but today, I have that : SSHException: Error reading SSH protocol banner

This is strange because it happens randomly on any connections. Is there any way to fix it ?

4
  • 39
    This happens if the server accepts the connection but the ssh daemon doesn't respond within 15 seconds. It could be network congestion, faulty switches, etc... but usually it means that the target server is bogged down or its sshd has hung. Recovery is to wait and try again. If you control the server, its a good time to check on its health.
    – tdelaney
    Commented Sep 1, 2014 at 16:49
  • 3
    You can reproduce this error by making 10 threads and opening/closing sftp connections as fast as you can on all of them. The sshd daemon can't respond in time, and the above exception is thrown. Commented Jan 15, 2015 at 20:21
  • 1
    I've just got the issue on one server. Openssh client connects fine, Paramiko fails. If I telnet the server, it doesn't write the line SSH-2.0-OpenSSH_6.0p1 immediately as all other servers do. Have no idea about the cause.
    – Equidamoid
    Commented May 25, 2015 at 12:55
  • 1
    I saw this exception when firewall rules are blocking certain level of access between hosts.
    – haridsv
    Commented Jul 14, 2022 at 10:47

8 Answers 8

46

It depends on what you mean by "fix". The underlying cause, as pointed out in the comments, are congestion/lack of resources. In that way, it's similar to some HTTP codes. That's the normal cause, it could be that the ssh server is returning the wrong header data.

429 Too Many Requests, tells the client to use rate limiting, or sometimes APIs will return 503 in a similar way, if you exceed your quota. The idea being, to try again later, with a delay.

You can attempt to handle this exception in your code, wait a little while, and try again. You can also edit your transport.py file, to set the banner timeout to something higher. If you have an application where it doesn't matter how quickly the server responds, you could set this to 60 seconds.

EDIT: Editing your transport file is no longer needed as per Greg's answer. When you call connect, you can pass a banner_timeout (which solves this issue), a timeout (for the underlying TCP), and an auth_timeout (waiting for authentication response). Greg's answer has a code example with banner_timeout that you can directly lift.

1
  • 1
    When I made my program, it try to connect something like 500 times on one machine. I think that the server was limiting my access in order to avoid bruteforce attacks (of course, it wasn't the objective of my program). Your answer is the right one in my case.
    – FunkySayu
    Commented Apr 7, 2015 at 14:18
29

Adding to TinBane's answers, suggesting to edit transport.py: you don't have to do that anymore.


Since Paramiko v. 1.15.0, released in 2015, (this PR, to be precise) you can configure that value when creating Paramiko connection, like this:

client = SSHClient()
client.connect('ssh.example.com', banner_timeout=200)

In the current version of Paramiko as of writing these words, v. 2.7.1, you have 2 more timeouts that you can configure when calling connect method, for these 3 in total (source):

  • banner_timeout - an optional timeout (in seconds) to wait for the SSH banner to be presented.
  • timeout - an optional timeout (in seconds) for the TCP connect
  • auth_timeout - an optional timeout (in seconds) to wait for an authentication response.
2
  • 3
    set all three to 60, but error is generated in under a second.
    – rob
    Commented Feb 3, 2021 at 9:07
  • Fixed my project by switching to a pool based system. Each time a new action is needed the pool is checked to see if a connection is ready to be used instead of tearing the connection down and recreating it each time. I think my hosting provider has implemented rate limiting on SSH connections. Pity the Paramiko timeout variables could not handle this for me.
    – rob
    Commented Feb 4, 2021 at 16:50
4

When changing the timeout value (as TinBane mentioned) in the transport.py file from 15 to higher the issue resolved partially. that is at line #484:

self.banner_timeout = 200 # It was 15

However, to resolve it permanently I added a static line to transport.py to declare the new higher value at the _check_banner(self): function.

Here is specifically the change:

  • It was like this:

 def _check_banner(self):
        for i in range(100):
            if i == 0:
                timeout = self.banner_timeout
            else:
                timeout = 2
  • After the permanent change became like this:

 def _check_banner(self):
        for i in range(100):
            if i == 0:
                timeout = self.banner_timeout
                timeout = 200 # <<<< Here is the explicit declaration 
            else:
                timeout = 2

0
3

paramiko seems to raise this error when I pass a non-existent filename to kwargs>key_filename. I'm sure there are other situations where this exception is raised nonsensically.

2

I had this issue with 12 parallel (12 threads) connections via single bastion. As I had to solve it "quick and dirty" I've added a sleep time.

for target in targets:
    deployer.deploy_target(target, asynchronous=True)

Changed to:

for target in targets:
    deployer.deploy_target(target, asynchronous=True)
    time.sleep(5)

This works for me. As well I've added a banner_timeout as was suggested above to make it more reliable.

client.connect(bastion_address, banner_timeout=60)
1

I'm very new to this so I doubt I'm really qualified to answer anyone's questions, however I feel I may offer a simple solution to this issue.

After i migrated from 1 machine to another, all my scripts that worked perfectly prior all stopped working with the following error after the move:

Exception: Error reading SSH protocol banner
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/paramiko/transport.py", line 2211, in _check_banner

I tried as many people suggested above of manually amending the transport.py file but all that happened for me was it took 60 seconds to timeout rather than the default 15.

Anyway i noticed that my new machine was running a slightly older version on paramiko so I simply upgraded this and it worked.

pip3 -U paramiko
1
  • The command is actually: pip install --upgrade paramiko
    – Gergely M
    Commented Dec 7, 2023 at 14:48
0

Well, I was also getting this with one of the juniper devices. The timeout didn't help at all. When I used pyex with this, it created multiple ssh/netconf sessions with juniper box. Once I changed the "set system services ssh connection-limit 10" From 5, it started working.

0

In my case, to speed up the connection download rate I have created a multiprocessing Pool of 10 processes, so 10 new ssh paramiko connections were active at the same time and downloading the data at the same time. When I increased this number to 20, I started getting this error. So, probably some congestion and too many connections active on one machine.

Not the answer you're looking for? Browse other questions tagged or ask your own question.