diff --git a/src/libs/ssh/sshconnection.cpp b/src/libs/ssh/sshconnection.cpp
index ebf233d3b6d946a65e8ed70d1690355ab26afee8..7d748d02677de21c14f659252ec7cad308b3d137 100644
--- a/src/libs/ssh/sshconnection.cpp
+++ b/src/libs/ssh/sshconnection.cpp
@@ -44,6 +44,7 @@
 #include <QMutex>
 #include <QMutexLocker>
 #include <QNetworkProxy>
+#include <QRegExp>
 #include <QTcpSocket>
 
 /*!
@@ -320,7 +321,7 @@ void SshConnectionPrivate::handleIncomingData()
         qDebug("state = %d, remote data size = %d", m_state,
             m_incomingData.count());
 #endif
-        if (m_state == SocketConnected)
+        if (m_serverId.isEmpty())
             handleServerId();
         handlePackets();
     } catch (SshServerException &e) {
@@ -335,39 +336,78 @@ void SshConnectionPrivate::handleIncomingData()
     }
 }
 
+// RFC 4253, 4.2.
 void SshConnectionPrivate::handleServerId()
 {
 #ifdef CREATOR_SSH_DEBUG
     qDebug("%s: incoming data size = %d, incoming data = '%s'",
         Q_FUNC_INFO, m_incomingData.count(), m_incomingData.data());
 #endif
-    const int idOffset = m_incomingData.indexOf("SSH-");
-    if (idOffset == -1)
+    const int newLinePos = m_incomingData.indexOf('\n');
+    if (newLinePos == -1)
+        return; // Not enough data yet.
+
+    // Lines not starting with "SSH-" are ignored.
+    if (!m_incomingData.startsWith("SSH-")) {
+        m_incomingData.remove(0, newLinePos + 1);
+        m_serverHasSentDataBeforeId = true;
         return;
-    m_incomingData.remove(0, idOffset);
-    if (m_incomingData.size() < 7)
-        return;
-    const QByteArray &version = m_incomingData.mid(4, 3);
-    if (version != "2.0") {
+    }
+
+    if (newLinePos > 255 - 1) {
+        throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
+            "Identification string too long.",
+            tr("Server identification string is %1 characters long, but the maximum "
+               "allowed length is 255.").arg(newLinePos + 1));
+    }
+
+    const bool hasCarriageReturn = m_incomingData.at(newLinePos - 1) == '\r';
+    m_serverId = m_incomingData.left(newLinePos);
+    if (hasCarriageReturn)
+        m_serverId.chop(1);
+    m_incomingData.remove(0, newLinePos + 1);
+
+    if (m_serverId.contains('\0')) {
+        throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
+            "Identification string contains illegal NUL character.",
+            tr("Server identification string contains illegal NUL character."));
+    }
+
+    // "printable US-ASCII characters, with the exception of whitespace characters
+    // and the minus sign"
+    QString legalString = QLatin1String("[]!\"#$!&'()*+,./0-9:;<=>?@A-Z[\\\\^_`a-z{|}~]+");
+    const QRegExp versionIdpattern(QString::fromLatin1("SSH-(%1)-%1(?: .+)?").arg(legalString));
+    if (!versionIdpattern.exactMatch(QString::fromLatin1(m_serverId))) {
+        throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
+            "Identification string is invalid.",
+            tr("Server Identification string '%1' is invalid.")
+                    .arg(QString::fromLatin1(m_serverId)));
+    }
+    const QString serverProtoVersion = versionIdpattern.cap(1);
+    if (serverProtoVersion != QLatin1String("2.0") && serverProtoVersion != QLatin1String("1.99")) {
         throw SshServerException(SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED,
             "Invalid protocol version.",
-            tr("Invalid protocol version: Expected '2.0', got '%1'.")
-            .arg(SshPacketParser::asUserString(version)));
+            tr("Server protocol version is '%1', but needs to be 2.0 or 1.99.")
+                    .arg(serverProtoVersion));
     }
-    const int endOffset = m_incomingData.indexOf("\r\n");
-    if (endOffset == -1)
-        return;
-    if (m_incomingData.at(7) != '-') {
+
+    // Disable this check to accept older OpenSSH servers that do this wrong.
+    if (serverProtoVersion == QLatin1String("2.0") && !hasCarriageReturn) {
+        throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
+            "Identification string is invalid.",
+            tr("Server identification string is invalid (missing carriage return)."));
+    }
+
+    if (serverProtoVersion == QLatin1String("1.99") && m_serverHasSentDataBeforeId) {
         throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
-            "Invalid server id.", tr("Invalid server id '%1'.")
-            .arg(SshPacketParser::asUserString(m_incomingData)));
+            "No extra data preceding identification string allowed for 1.99.",
+            tr("Server reports protocol version 1.99, but sends data "
+               "before the identification string, which is not allowed."));
     }
 
     m_keyExchange.reset(new SshKeyExchange(m_sendFacility));
-    m_serverId = m_incomingData.left(endOffset);
     m_keyExchange->sendKexInitPacket(m_serverId);
     m_keyExchangeState = KexInitSent;
-    m_incomingData.remove(0, endOffset + 2);
 }
 
 void SshConnectionPrivate::handlePackets()
@@ -645,6 +685,8 @@ void SshConnectionPrivate::connectToHost()
     m_error = SshNoError;
     m_ignoreNextPacket = false;
     m_errorString.clear();
+    m_serverId.clear();
+    m_serverHasSentDataBeforeId = false;
 
     try {
         if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationByKey)
diff --git a/src/libs/ssh/sshconnection_p.h b/src/libs/ssh/sshconnection_p.h
index bdf0c26c960d880bd81d985183ef4f1deab6065e..797d7364374fe8ac0ebfeb30323b9e0a1ceed2fc 100644
--- a/src/libs/ssh/sshconnection_p.h
+++ b/src/libs/ssh/sshconnection_p.h
@@ -165,6 +165,7 @@ private:
     SshConnection *m_conn;
     quint64 m_lastInvalidMsgSeqNr;
     QByteArray m_serverId;
+    bool m_serverHasSentDataBeforeId;
 };
 
 } // namespace Internal