risingwavelabs/risingwave · error · PsqlError
LDAP bind failed
Error message
LDAP bind failed
What it means
Once the user's DN is found, search_and_bind binds as that DN with the end-user's password to authenticate them. simple_bind errors are mapped to this StartupError before the connection is unbound; a non-success result code from bind_result.success() is then matched separately. This is the final user-credential check — a failure means the username/password supplied by the psql client are wrong for the directory, or the DN found cannot bind.
Source
Thrown at src/utils/pgwire/src/ldap_auth.rs:532
.await
.map_err(|e| {
PsqlError::StartupError(anyhow!(e).context("LDAP search failed").into())
})?;
// If no user found, authentication fails
let search_entries: Vec<SearchEntry> =
rs.0.into_iter().map(SearchEntry::construct).collect();
if search_entries.is_empty() {
return Ok(false);
}
// Attempt to bind with the user's DN and password
let user_dn = &search_entries[0].dn;
let bind_result = ldap
.simple_bind(user_dn, password)
.await
.map_err(|e| PsqlError::StartupError(anyhow!(e).context("LDAP bind failed").into()));
// Explicitly unbind the connection
let _ = ldap.unbind().await;
let bind_result = bind_result?;
match bind_result.success() {
Ok(_) => Ok(true),
Err(e) => {
tracing::error!(error = %e.as_report(), "LDAP bind unsuccessful");
Err(PsqlError::StartupError(
anyhow!(e).context("LDAP bind failed").into(),
))
}
}
}
/// Simple bind authentication
async fn simple_bind(&self, username: &str, password: &str) -> PsqlResult<bool> {View on GitHub (pinned to 6469eb736d)
Solutions
- Have the user retry with the correct directory password (this is usually simple credential failure)
- Verify the matched DN can bind: ldapwhoami -D 'user_dn' -w 'password'
- Use ldaps:// or StartTLS if the directory rejects simple binds over insecure connections
- Tighten search_filter so only bindable user objects match (e.g. add (objectClass=user))
Example fix
// before: filter matches groups too
search_filter = '(cn={username})'
// after: restrict to user objects
search_filter = '(&(objectClass=user)(sAMAccountName={username}))' Defensive patterns
Strategy: try-catch
Validate before calling
// confirm a test user DN can bind before pointing RisingWave at the directory # ldapwhoami -H ldaps://ldap.corp:636 -D 'cn=testuser,ou=users,dc=corp,dc=com' -w 'password'
Try / catch
catch PsqlError::StartupError 'LDAP bind failed'; on invalidCredentials (49) return a clean auth-failure to the psql client rather than a startup error; log only the DN, never the password
Prevention
- Restrict search_filter to bindable user objects with (objectClass=user) etc.
- Communicate that passwords are directory passwords, not RisingWave-local ones
- Use ldaps:// or StartTLS since many directories reject simple binds over plaintext
- Map expired/locked account result codes to user-friendly messages
When it happens
Trigger: ldap.simple_bind(user_dn, password) returns Err (mapped here), or later bind_result.success() yields an error result code like invalidCredentials
Common situations: End user typed the wrong password in psql; password expired or account locked; directory disallows simple binds for user entries (e.g. AD default forbids simple bind over plaintext); the matched entry is not actually a bindable user (found a group or contact object).
Related errors
- LDAP bind as search user failed
- Both `access_key` and `secret_key` must be provided
- No auth method specified for Vault backend
- Vault app role login failed: {} - {}
- NATS connect mode `user_and_password` requires both `user` a
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/883be8ba619df5bb.
Report an issue: GitHub.