diff --git a/src/box/auth_ldap.c b/src/box/auth_ldap.c
index b96b1d9dd4bb59bc927988087c85d17ffc00b510..0675835c8fd25af4c600effa852bbd554a9e1697 100644
--- a/src/box/auth_ldap.c
+++ b/src/box/auth_ldap.c
@@ -292,7 +292,7 @@ auth_ldap_new(void)
 {
 	struct auth_method *method = xmalloc(sizeof(*method));
 	method->name = AUTH_LDAP_NAME;
-	method->flags = 0;
+	method->flags = AUTH_METHOD_PASSWORDLESS_DATA_PREPARE;
 	method->auth_method_delete = auth_ldap_delete;
 	method->auth_data_prepare = auth_ldap_data_prepare;
 	method->auth_request_prepare = auth_ldap_request_prepare;
diff --git a/src/box/authentication.h b/src/box/authentication.h
index 35fd4cfe212a7943d86454ec59d23a0e560897b5..a843a1b8cfd31d48dbeaef396789000cf2dbdd0d 100644
--- a/src/box/authentication.h
+++ b/src/box/authentication.h
@@ -53,6 +53,12 @@ enum auth_method_flag {
 	 * communication channel is encrypted (e.g. with SSL/TLS).
 	 */
 	AUTH_METHOD_REQUIRES_ENCRYPTION = 1 << 0,
+	/**
+	 * Set if the authentication method does not need
+	 * password in auth_method::auth_data_prepare.
+	 * This is opt-in because most methods require password.
+	 */
+	AUTH_METHOD_PASSWORDLESS_DATA_PREPARE = 1 << 1,
 };
 
 /**
diff --git a/src/box/lua/misc.cc b/src/box/lua/misc.cc
index 1d0c517bb6c3f90ede7a40b32024611e5c9aeaa0..f0676873afe68bc2e7f932ea4a10a13b25ad560c 100644
--- a/src/box/lua/misc.cc
+++ b/src/box/lua/misc.cc
@@ -236,6 +236,28 @@ lbox_generate_space_id(lua_State *L)
 
 /** {{{ Helper that generates user auth data. **/
 
+/**
+ * Takes authentication method name (e.g. 'chap-sha1').
+ * Returns true if password is needed to produce auth data, false otherwise.
+ * Raises Lua error if the specified authentication method doesn't exist.
+ */
+static int
+lbox_prepare_auth_needs_password(lua_State *L)
+{
+	size_t method_name_len;
+	const char *method_name = luaL_checklstring(L, 1, &method_name_len);
+	const struct auth_method *method = auth_method_by_name(method_name,
+							       method_name_len);
+	if (method == NULL) {
+		diag_set(ClientError, ER_UNKNOWN_AUTH_METHOD,
+			 tt_cstr(method_name, method_name_len));
+		return luaT_error(L);
+	}
+	int pwdless = method->flags & AUTH_METHOD_PASSWORDLESS_DATA_PREPARE;
+	lua_pushboolean(L, !pwdless);
+	return 1;
+}
+
 /**
  * Takes authentication method name (e.g. 'chap-sha1'), password and user name.
  * Returns authentication data that can be stored in the _user space.
@@ -507,6 +529,7 @@ void
 box_lua_misc_init(struct lua_State *L)
 {
 	static const struct luaL_Reg boxlib_internal[] = {
+		{"prepare_auth_needs_password", lbox_prepare_auth_needs_password},
 		{"prepare_auth", lbox_prepare_auth},
 		{"select", lbox_select},
 		{"new_tuple_format", lbox_tuple_format_new},
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index ea072a45622aa254b798b9155b4177fcb20e8172..12a439ad3cca86b4740f14d4e0aea364d6089dae 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -3205,10 +3205,14 @@ box.schema.user.password = function(password, name)
     return internal.prepare_auth(box.cfg.auth_type, password, name)
 end
 
-local function prepare_auth_list(password, name)
+local function prepare_auth_list_needs_password(auth_type)
+    return internal.prepare_auth_needs_password(auth_type)
+end
+
+local function prepare_auth_list(auth_type, password, name)
     return {
-        [box.cfg.auth_type] =
-            internal.prepare_auth(box.cfg.auth_type, password, name)
+        [auth_type] =
+            internal.prepare_auth(auth_type, password, name)
     }
 end
 
@@ -3228,9 +3232,11 @@ end
 
 local function chpasswd(uid, new_password, name)
     local _user = box.space[box.schema.USER_ID]
+    local auth_type = box.cfg.auth_type
+    local auth_list = prepare_auth_list(auth_type, new_password, name)
     local auth_history = prepare_auth_history(uid)
     check_password(new_password, auth_history)
-    _user:update({uid}, {{'=', 5, prepare_auth_list(new_password, name)},
+    _user:update({uid}, {{'=', 5, auth_list},
                          {'=', 6, auth_history},
                          {'=', 7, math.floor(fiber.time())}})
 end
@@ -3257,17 +3263,25 @@ end
 box.schema.user.create = function(name, opts)
     local uid = user_or_role_resolve(name)
     opts = opts or {}
-    check_param_table(opts, { password = 'string', if_not_exists = 'boolean' })
+    check_param_table(opts, {auth_type = 'string',
+                             password = 'string',
+                             if_not_exists = 'boolean'})
     if uid then
         if not opts.if_not_exists then
             box.error(box.error.USER_EXISTS, name)
         end
         return
     end
+    local auth_type = opts.auth_type or box.cfg.auth_type
     local auth_list
-    if opts.password then
+    if not prepare_auth_list_needs_password(auth_type) then
+        if opts.password then
+            log.warn(auth_type .. " doesn't need password")
+        end
+        auth_list = prepare_auth_list(auth_type, '', name)
+    elseif opts.password then
         check_password(opts.password)
-        auth_list = prepare_auth_list(opts.password, name)
+        auth_list = prepare_auth_list(auth_type, opts.password, name)
     else
         auth_list = setmap({})
     end