diff --git a/changelogs/fragments/34722-ssh-sshpass-prompt-variable.yml b/changelogs/fragments/34722-ssh-sshpass-prompt-variable.yml
new file mode 100644
index 00000000000..b9f386bea6f
--- /dev/null
+++ b/changelogs/fragments/34722-ssh-sshpass-prompt-variable.yml
@@ -0,0 +1,2 @@
+minor_changes:
+- ssh - connection plugin now supports a new variable ``sshpass_prompt`` which gets passed to ``sshpass`` allowing the user to set a custom substring to search for a password prompt (requires sshpass 1.06+)
diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py
index 479e1919cee..5a51ee3ba87 100644
--- a/lib/ansible/plugins/connection/ssh.py
+++ b/lib/ansible/plugins/connection/ssh.py
@@ -48,6 +48,17 @@ DOCUMENTATION = '''
               - name: ansible_password
               - name: ansible_ssh_pass
               - name: ansible_ssh_password
+      sshpass_prompt:
+          description: Password prompt that sshpass should search for. Supported by sshpass 1.06 and up.
+          default: ''
+          ini:
+              - section: 'ssh_connection'
+                key: 'sshpass_prompt'
+          env:
+              - name: ANSIBLE_SSHPASS_PROMPT
+          vars:
+              - name: ansible_sshpass_prompt
+          version_added: '2.10'
       ssh_args:
           description: Arguments to pass to all ssh cli tools
           default: '-C -o ControlMaster=auto -o ControlPersist=60s'
@@ -331,13 +342,19 @@ def _handle_error(remaining_retries, command, return_tuple, no_log, host, displa
             raise AnsibleAuthenticationFailure(msg)
 
         # sshpass returns codes are 1-6. We handle 5 previously, so this catches other scenarios.
-        # No exception is raised, so the connection is retried.
+        # No exception is raised, so the connection is retried - except when attempting to use
+        # sshpass_prompt with an sshpass that won't let us pass -P, in which case we fail loudly.
         elif return_tuple[0] in [1, 2, 3, 4, 6]:
             msg = 'sshpass error:'
             if no_log:
                 msg = '{0} <error censored due to no log>'.format(msg)
             else:
-                msg = '{0} {1}'.format(msg, to_native(return_tuple[2]).rstrip())
+                details = to_native(return_tuple[2]).rstrip()
+                if "sshpass: invalid option -- 'P'" in details:
+                    details = 'Installed sshpass version does not support customized password prompts. ' \
+                              'Upgrade sshpass to use sshpass_prompt, or otherwise switch to ssh keys.'
+                    raise AnsibleError('{0} {1}'.format(msg, details))
+                msg = '{0} {1}'.format(msg, details)
 
     if return_tuple[0] == 255:
         SSH_ERROR = True
@@ -562,6 +579,10 @@ class Connection(ConnectionBase):
             self.sshpass_pipe = os.pipe()
             b_command += [b'sshpass', b'-d' + to_bytes(self.sshpass_pipe[0], nonstring='simplerepr', errors='surrogate_or_strict')]
 
+            password_prompt = self.get_option('sshpass_prompt')
+            if password_prompt:
+                b_command += [b'-P', to_bytes(password_prompt, errors='surrogate_or_strict')]
+
         if binary == 'ssh':
             b_command += [to_bytes(self._play_context.ssh_executable, errors='surrogate_or_strict')]
         else:
diff --git a/test/integration/targets/connection_ssh/runme.sh b/test/integration/targets/connection_ssh/runme.sh
index a24ff048c50..e7b2b21f0b0 100755
--- a/test/integration/targets/connection_ssh/runme.sh
+++ b/test/integration/targets/connection_ssh/runme.sh
@@ -1,6 +1,48 @@
 #!/usr/bin/env bash
 
-set -eux
+set -ux
+
+# We skip this whole section if the test node doesn't have sshpass on it.
+if command -v sshpass > /dev/null; then
+    # Check if our sshpass supports -P
+    sshpass -P foo > /dev/null
+    sshpass_supports_prompt=$?
+    if [[ $sshpass_supports_prompt -eq 0 ]]; then
+        # If the prompt is wrong, we'll end up hanging (due to sshpass hanging).
+        # We should probably do something better here, like timing out in Ansible,
+        # but this has been the behavior for a long time, before we supported custom
+        # password prompts.
+        #
+        # So we search for a custom password prompt that is clearly wrong and call
+        # ansible with timeout. If we time out, our custom prompt was successfully
+        # searched for. It's a weird way of doing things, but it does ensure
+        # that the flag gets passed to sshpass.
+        timeout 5 ansible -m ping \
+            -e ansible_connection=ssh \
+            -e ansible_sshpass_prompt=notThis: \
+            -e ansible_password=foo \
+            -e ansible_user=definitelynotroot \
+	    -i test_connection.inventory \
+            ssh-pipelining
+        ret=$?
+        if [[ $ret -ne 124 ]]; then
+            echo "Expected to time out and we did not. Exiting with failure."
+     	exit 1
+        fi
+    else
+        ansible -m ping \
+            -e ansible_connection=ssh \
+            -e ansible_sshpass_prompt=notThis: \
+            -e ansible_password=foo \
+            -e ansible_user=definitelynotroot \
+	    -i test_connection.inventory \
+            ssh-pipelining | grep 'customized password prompts'
+        ret=$?
+        [[ $ret -eq 0 ]] || exit $ret
+    fi
+fi
+
+set -e
 
 # temporary work-around for issues due to new scp filename checking
 # https://github.com/ansible/ansible/issues/52640