Blob Blame History Raw
From 53cecf3abcc08724ae9b21fd02b8423fd39e7086 Mon Sep 17 00:00:00 2001
From: progier389 <progier@redhat.com>
Date: Fri, 17 Nov 2023 14:41:51 +0100
Subject: [PATCH] Issue 5984 - Crash when paged result search are abandoned -
 fix + fix2 (#5985 and #5987)

Notice: This cherry-pick include two commit:
df7dd8320 Issue 5984 - Crash when paged result search are abandoned - fix2 (#5987)
06bd08629 Issue 5984 - Crash when paged result search are abandoned (#5985)
The reason is that cherry pick of #5985 generates lots of conflict in __init.py
 and #5987 only revert that file ==> So it is easier and safer to keep the original
  file.

* Issue 5984 - Crash when paged result search are abandoned

Problem:
  Fix #4551 has changed the lock that protects the paged result data
  within a connection. But the abandon operation attempts to free
  the paged search result with the connection lock.
  This leads to race condition and double free causing an heap
  corruption and a SIGSEGV.

  Solution:
   - Get a copy of the operation data that needs to be logged.
   - Unlock the connection mutex (to avoid deadlock risk)
   - Free the paged result while holding the paged result lock.

Issue: 5984

Reviewed by: @tbordaz (Thanks!)

(cherry picked from commit 06bd0862956672eb76276cab5c1dd906fe5a7eec)
---
 .../paged_results/paged_results_test.py       | 758 +++++++++---------
 ldap/servers/slapd/abandon.c                  |  23 +-
 ldap/servers/slapd/opshared.c                 |   4 +-
 ldap/servers/slapd/pagedresults.c             |   8 +-
 ldap/servers/slapd/proto-slap.h               |   2 +-
 5 files changed, 392 insertions(+), 403 deletions(-)

diff --git a/dirsrvtests/tests/suites/paged_results/paged_results_test.py b/dirsrvtests/tests/suites/paged_results/paged_results_test.py
index ae2627b75..a030824c6 100644
--- a/dirsrvtests/tests/suites/paged_results/paged_results_test.py
+++ b/dirsrvtests/tests/suites/paged_results/paged_results_test.py
@@ -1,21 +1,32 @@
 # --- BEGIN COPYRIGHT BLOCK ---
-# Copyright (C) 2016 Red Hat, Inc.
+# Copyright (C) 2020 Red Hat, Inc.
 # All rights reserved.
 #
 # License: GPL (version 3 or any later version).
 # See LICENSE for details.
 # --- END COPYRIGHT BLOCK ---
 #
-from random import sample
+import socket
+from random import sample, randrange
 
 import pytest
 from ldap.controls import SimplePagedResultsControl, GetEffectiveRightsControl
 from lib389.tasks import *
 from lib389.utils import *
 from lib389.topologies import topology_st
-from lib389._constants import DN_LDBM, DN_DM, DEFAULT_SUFFIX, BACKEND_NAME, PASSWORD
+from lib389._constants import DN_LDBM, DN_DM, DEFAULT_SUFFIX
+from lib389._controls import SSSRequestControl
+from lib389.idm.user import UserAccount, UserAccounts
+from lib389.cli_base import FakeArgs
+from lib389.config import LDBMConfig
+from lib389.dbgen import dbgen_users
 
-from sss_control import SSSRequestControl
+from lib389.idm.organization import Organization
+from lib389.idm.organizationalunit import OrganizationalUnit
+from lib389.backend import Backends
+from lib389._mapped_object import DSLdapObject
+
+pytestmark = pytest.mark.tier1
 
 DEBUGGING = os.getenv('DEBUGGING', False)
 
@@ -26,9 +37,8 @@ else:
 
 log = logging.getLogger(__name__)
 
-TEST_USER_NAME = 'simplepaged_test'
-TEST_USER_DN = 'uid={},{}'.format(TEST_USER_NAME, DEFAULT_SUFFIX)
 TEST_USER_PWD = 'simplepaged_test'
+
 NEW_SUFFIX_1_NAME = 'test_parent'
 NEW_SUFFIX_1 = 'o={}'.format(NEW_SUFFIX_1_NAME)
 NEW_SUFFIX_2_NAME = 'child'
@@ -36,34 +46,90 @@ NEW_SUFFIX_2 = 'ou={},{}'.format(NEW_SUFFIX_2_NAME, NEW_SUFFIX_1)
 NEW_BACKEND_1 = 'parent_base'
 NEW_BACKEND_2 = 'child_base'
 
+OLD_HOSTNAME = socket.gethostname()
+if os.getuid() == 0:
+    socket.sethostname('localhost')
+HOSTNAME = socket.gethostname()
+IP_ADDRESS = socket.gethostbyname(HOSTNAME)
+OLD_IP_ADDRESS = socket.gethostbyname(OLD_HOSTNAME)
+
 
 @pytest.fixture(scope="module")
-def test_user(topology_st, request):
+def create_40k_users(topology_st, request):
+    inst = topology_st.standalone
+
+    # Prepare return value
+    retval = FakeArgs()
+    retval.inst = inst
+    retval.bename = '40k'
+    retval.suffix = 'o=%s' % retval.bename
+    ldifdir = inst.get_ldif_dir()
+    retval.ldif_file = '%s/%s.ldif' % (ldifdir, retval.bename)
+
+    # Create new backend
+    bes = Backends(inst)
+    be_1 = bes.create(properties={
+        'cn': retval.bename,
+        'nsslapd-suffix': retval.suffix,
+    })
+
+    # Set paged search lookthrough limit
+    ldbmconfig = LDBMConfig(inst)
+    ldbmconfig.replace('nsslapd-pagedlookthroughlimit', b'100000')
+
+    # Create ldif and import it.
+    dbgen_users(inst, 40000, retval.ldif_file, retval.suffix)
+    # tasks = Tasks(inst)
+    # args = {TASK_WAIT: True}
+    # tasks.importLDIF(retval.suffix, None, retval.ldif_file, args)
+    inst.stop()
+    assert inst.ldif2db(retval.bename, None, None, None, retval.ldif_file, None)
+    inst.start()
+
+    # And set an aci allowing anonymous read
+    log.info('Adding ACI to allow our test user to search')
+    ACI_TARGET = '(targetattr != "userPassword || aci")'
+    ACI_ALLOW = '(version 3.0; acl "Enable anonymous access";allow (read, search, compare)'
+    ACI_SUBJECT = '(userdn = "ldap:///anyone");)'
+    ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+    o_1 = Organization(inst, retval.suffix)
+    o_1.set('aci', ACI_BODY)
+
+    return retval
+
+
+@pytest.fixture(scope="module")
+def create_user(topology_st, request):
     """User for binding operation"""
 
-    log.info('Adding user {}'.format(TEST_USER_DN))
-    try:
-        topology_st.standalone.add_s(Entry((TEST_USER_DN, {
-            'objectclass': 'top person'.split(),
-            'objectclass': 'organizationalPerson',
-            'objectclass': 'inetorgperson',
-            'cn': TEST_USER_NAME,
-            'sn': TEST_USER_NAME,
-            'userpassword': TEST_USER_PWD,
-            'mail': '%s@redhat.com' % TEST_USER_NAME,
-            'uid': TEST_USER_NAME
-        })))
-    except ldap.LDAPError as e:
-        log.error('Failed to add user (%s): error (%s)' % (TEST_USER_DN,
-                                                           e.message['desc']))
-        raise e
+    log.info('Adding user simplepaged_test')
+    new_uri = topology_st.standalone.ldapuri.replace(OLD_HOSTNAME, HOSTNAME)
+    topology_st.standalone.ldapuri = new_uri
+    users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX)
+    user = users.create(properties={
+        'uid': 'simplepaged_test',
+        'cn': 'simplepaged_test',
+        'sn': 'simplepaged_test',
+        'uidNumber': '1234',
+        'gidNumber': '1234',
+        'homeDirectory': '/home/simplepaged_test',
+        'userPassword': TEST_USER_PWD,
+    })
+
+    # Now add the ACI so simplepage_test can read the users ...
+    ACI_BODY = ensure_bytes('(targetattr= "uid || sn || dn")(version 3.0; acl "Allow read for user"; allow (read,search,compare) userdn = "ldap:///all";)')
+    topology_st.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_REPLACE, 'aci', ACI_BODY)])
 
     def fin():
-        log.info('Deleting user {}'.format(TEST_USER_DN))
-        topology_st.standalone.delete_s(TEST_USER_DN)
+        log.info('Deleting user simplepaged_test')
+        if not DEBUGGING:
+            user.delete()
+        if os.getuid() == 0:
+            socket.sethostname(OLD_HOSTNAME)
 
     request.addfinalizer(fin)
 
+    return user
 
 @pytest.fixture(scope="module")
 def new_suffixes(topology_st):
@@ -72,47 +138,40 @@ def new_suffixes(topology_st):
     """
 
     log.info('Adding suffix:{} and backend: {}'.format(NEW_SUFFIX_1, NEW_BACKEND_1))
-    topology_st.standalone.backend.create(NEW_SUFFIX_1,
-                                          {BACKEND_NAME: NEW_BACKEND_1})
-    topology_st.standalone.mappingtree.create(NEW_SUFFIX_1,
-                                              bename=NEW_BACKEND_1)
-    try:
-        topology_st.standalone.add_s(Entry((NEW_SUFFIX_1, {
-            'objectclass': 'top',
-            'objectclass': 'organization',
-            'o': NEW_SUFFIX_1_NAME
-        })))
-    except ldap.LDAPError as e:
-        log.error('Failed to add suffix ({}): error ({})'.format(NEW_SUFFIX_1,
-                                                                 e.message['desc']))
-        raise
 
-    log.info('Adding suffix:{} and backend: {}'.format(NEW_SUFFIX_2, NEW_BACKEND_2))
-    topology_st.standalone.backend.create(NEW_SUFFIX_2,
-                                          {BACKEND_NAME: NEW_BACKEND_2})
-    topology_st.standalone.mappingtree.create(NEW_SUFFIX_2,
-                                              bename=NEW_BACKEND_2,
-                                              parent=NEW_SUFFIX_1)
-
-    try:
-        topology_st.standalone.add_s(Entry((NEW_SUFFIX_2, {
-            'objectclass': 'top',
-            'objectclass': 'organizationalunit',
-            'ou': NEW_SUFFIX_2_NAME
-        })))
-    except ldap.LDAPError as e:
-        log.error('Failed to add suffix ({}): error ({})'.format(NEW_SUFFIX_2,
-                                                                 e.message['desc']))
-        raise
+    bes = Backends(topology_st.standalone)
 
+    bes.create(properties={
+        'cn': 'NEW_BACKEND_1',
+        'nsslapd-suffix': NEW_SUFFIX_1,
+    })
+    # Create the root objects with their ACI
     log.info('Adding ACI to allow our test user to search')
     ACI_TARGET = '(targetattr != "userPassword || aci")'
     ACI_ALLOW = '(version 3.0; acl "Enable anonymous access";allow (read, search, compare)'
     ACI_SUBJECT = '(userdn = "ldap:///anyone");)'
     ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
 
-    mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
-    topology_st.standalone.modify_s(NEW_SUFFIX_1, mod)
+    o_1 = Organization(topology_st.standalone, NEW_SUFFIX_1)
+    o_1.create(properties={
+        'o': NEW_SUFFIX_1_NAME,
+        'aci': ACI_BODY,
+    })
+
+    log.info('Adding suffix:{} and backend: {}'.format(NEW_SUFFIX_2, NEW_BACKEND_2))
+    be_2 = bes.create(properties={
+        'cn': 'NEW_BACKEND_2',
+        'nsslapd-suffix': NEW_SUFFIX_2,
+    })
+
+    # We have to adjust the MT to say that BE_1 is a parent.
+    mt = be_2.get_mapping_tree()
+    mt.set_parent(NEW_SUFFIX_1)
+
+    ou_2 = OrganizationalUnit(topology_st.standalone, NEW_SUFFIX_2)
+    ou_2.create(properties={
+        'ou': NEW_SUFFIX_2_NAME
+    })
 
 
 def add_users(topology_st, users_num, suffix):
@@ -122,72 +181,54 @@ def add_users(topology_st, users_num, suffix):
     """
 
     users_list = []
+    users = UserAccounts(topology_st.standalone, suffix, rdn=None)
+
     log.info('Adding %d users' % users_num)
     for num in sample(range(1000), users_num):
         num_ran = int(round(num))
         USER_NAME = 'test%05d' % num_ran
-        USER_DN = 'uid=%s,%s' % (USER_NAME, suffix)
-        users_list.append(USER_DN)
-        try:
-            topology_st.standalone.add_s(Entry((USER_DN, {
-                'objectclass': 'top person'.split(),
-                'objectclass': 'organizationalPerson',
-                'objectclass': 'inetorgperson',
-                'cn': USER_NAME,
-                'sn': USER_NAME,
-                'userpassword': 'pass%s' % num_ran,
-                'mail': '%s@redhat.com' % USER_NAME,
-                'uid': USER_NAME})))
-        except ldap.LDAPError as e:
-            log.error('Failed to add user (%s): error (%s)' % (USER_DN,
-                                                               e.message['desc']))
-            raise e
+
+        user = users.create(properties={
+            'uid': USER_NAME,
+            'sn': USER_NAME,
+            'cn': USER_NAME,
+            'uidNumber': '%s' % num_ran,
+            'gidNumber': '%s' % num_ran,
+            'homeDirectory': '/home/%s' % USER_NAME,
+            'mail': '%s@redhat.com' % USER_NAME,
+            'userpassword': 'pass%s' % num_ran,
+        })
+        users_list.append(user)
     return users_list
 
 
-def del_users(topology_st, users_list):
+def del_users(users_list):
     """Delete users with DNs from given list"""
 
     log.info('Deleting %d users' % len(users_list))
-    for user_dn in users_list:
-        try:
-            topology_st.standalone.delete_s(user_dn)
-        except ldap.LDAPError as e:
-            log.error('Failed to delete user (%s): error (%s)' % (user_dn,
-                                                                  e.message['desc']))
-            raise e
+    for user in users_list:
+        user.delete()
 
 
 def change_conf_attr(topology_st, suffix, attr_name, attr_value):
-    """Change configurational attribute in the given suffix.
+    """Change configuration attribute in the given suffix.
 
     Returns previous attribute value.
     """
 
-    try:
-        entries = topology_st.standalone.search_s(suffix, ldap.SCOPE_BASE,
-                                                  'objectclass=top',
-                                                  [attr_name])
-        attr_value_bck = entries[0].data.get(attr_name)
-        log.info('Set %s to %s. Previous value - %s. Modified suffix - %s.' % (
-            attr_name, attr_value, attr_value_bck, suffix))
-        if attr_value is None:
-            topology_st.standalone.modify_s(suffix, [(ldap.MOD_DELETE,
-                                                      attr_name,
-                                                      attr_value)])
-        else:
-            topology_st.standalone.modify_s(suffix, [(ldap.MOD_REPLACE,
-                                                      attr_name,
-                                                      attr_value)])
-    except ldap.LDAPError as e:
-        log.error('Failed to change attr value (%s): error (%s)' % (attr_name,
-                                                                    e.message['desc']))
-        raise e
+    entry = DSLdapObject(topology_st.standalone, suffix)
 
+    attr_value_bck = entry.get_attr_val_bytes(attr_name)
+    log.info('Set %s to %s. Previous value - %s. Modified suffix - %s.' % (
+        attr_name, attr_value, attr_value_bck, suffix))
+    if attr_value is None:
+        entry.remove_all(attr_name)
+    else:
+        entry.replace(attr_name, attr_value)
     return attr_value_bck
 
 
-def paged_search(topology_st, suffix, controls, search_flt, searchreq_attrlist):
+def paged_search(conn, suffix, controls, search_flt, searchreq_attrlist, abandon_rate=0):
     """Search at the DEFAULT_SUFFIX with ldap.SCOPE_SUBTREE
     using Simple Paged Control(should the first item in the
     list controls.
@@ -206,14 +247,17 @@ def paged_search(topology_st, suffix, controls, search_flt, searchreq_attrlist):
                                                     searchreq_attrlist,
                                                     req_pr_ctrl.size,
                                                     str(controls)))
-    msgid = topology_st.standalone.search_ext(suffix,
-                                              ldap.SCOPE_SUBTREE,
-                                              search_flt,
-                                              searchreq_attrlist,
-                                              serverctrls=controls)
+    msgid = conn.search_ext(suffix, ldap.SCOPE_SUBTREE, search_flt, searchreq_attrlist, serverctrls=controls)
+    log.info('Getting page %d' % (pages,))
     while True:
-        log.info('Getting page %d' % (pages,))
-        rtype, rdata, rmsgid, rctrls = topology_st.standalone.result3(msgid)
+        try:
+            rtype, rdata, rmsgid, rctrls = conn.result3(msgid, timeout=0.001)
+        except ldap.TIMEOUT:
+            if pages > 0 and abandon_rate>0 and randrange(100)<abandon_rate:
+                conn.abandon(msgid)
+                log.info('Paged result search is abandonned.')
+                return all_results
+            continue
         log.debug('Data: {}'.format(rdata))
         all_results.extend(rdata)
         pages += 1
@@ -228,27 +272,25 @@ def paged_search(topology_st, suffix, controls, search_flt, searchreq_attrlist):
                 # Copy cookie from response control to request control
                 log.debug('Cookie: {}'.format(pctrls[0].cookie))
                 req_pr_ctrl.cookie = pctrls[0].cookie
-                msgid = topology_st.standalone.search_ext(suffix,
-                                                          ldap.SCOPE_SUBTREE,
-                                                          search_flt,
-                                                          searchreq_attrlist,
-                                                          serverctrls=controls)
+                msgid = conn.search_ext(suffix, ldap.SCOPE_SUBTREE, search_flt, searchreq_attrlist, serverctrls=controls)
             else:
                 break  # No more pages available
         else:
             break
+        log.info('Getting page %d' % (pages,))
 
     assert not pctrls[0].cookie
     return all_results
 
 
-@pytest.mark.parametrize("page_size,users_num",
-                         [(6, 5), (5, 5), (5, 25)])
-def test_search_success(topology_st, test_user, page_size, users_num):
+@pytest.mark.parametrize("page_size,users_num", [(6, 5), (5, 5), (5, 25)])
+def test_search_success(topology_st, create_user, page_size, users_num):
     """Verify that search with a simple paged results control
     returns all entries it should without errors.
 
     :id: ddd15b70-64f1-4a85-a793-b24761e50354
+    :customerscenario: True
+    :parametrized: yes
     :feature: Simple paged results
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
@@ -264,21 +306,16 @@ def test_search_success(topology_st, test_user, page_size, users_num):
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
-    try:
-        log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+    log.info('Set user bind %s ' % create_user)
+    conn = create_user.bind(TEST_USER_PWD)
 
-        req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
+    req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
+    all_results = paged_search(conn, DEFAULT_SUFFIX, [req_ctrl], search_flt, searchreq_attrlist)
 
-        all_results = paged_search(topology_st, DEFAULT_SUFFIX, [req_ctrl],
-                                   search_flt, searchreq_attrlist)
+    log.info('%d results' % len(all_results))
+    assert len(all_results) == len(users_list)
 
-        log.info('%d results' % len(all_results))
-        assert len(all_results) == len(users_list)
-    finally:
-        log.info('Set Directory Manager bind back (test_search_success)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
+    del_users(users_list)
 
 
 @pytest.mark.parametrize("page_size,users_num,suffix,attr_name,attr_value,expected_err", [
@@ -292,13 +329,15 @@ def test_search_success(topology_st, test_user, page_size, users_num):
      ldap.SIZELIMIT_EXCEEDED),
     (5, 50, 'cn=config,%s' % DN_LDBM, 'nsslapd-lookthroughlimit', '20',
      ldap.ADMINLIMIT_EXCEEDED)])
-def test_search_limits_fail(topology_st, test_user, page_size, users_num,
+def test_search_limits_fail(topology_st, create_user, page_size, users_num,
                             suffix, attr_name, attr_value, expected_err):
     """Verify that search with a simple paged results control
     throws expected exceptoins when corresponding limits are
     exceeded.
 
     :id: e3067107-bd6d-493d-9989-3e641a9337b0
+    :customerscenario: True
+    :parametrized: yes
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
     :steps:
@@ -321,7 +360,7 @@ def test_search_limits_fail(topology_st, test_user, page_size, users_num,
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         log.info('Create simple paged results control instance')
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
@@ -330,11 +369,8 @@ def test_search_limits_fail(topology_st, test_user, page_size, users_num,
             sort_ctrl = SSSRequestControl(True, ['sn'])
             controls.append(sort_ctrl)
         log.info('Initiate ldapsearch with created control instance')
-        msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                  ldap.SCOPE_SUBTREE,
-                                                  search_flt,
-                                                  searchreq_attrlist,
-                                                  serverctrls=controls)
+        msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                search_flt, searchreq_attrlist, serverctrls=controls)
 
         time_val = conf_param_dict.get('nsslapd-timelimit')
         if time_val:
@@ -345,12 +381,11 @@ def test_search_limits_fail(topology_st, test_user, page_size, users_num,
         pctrls = []
         while True:
             log.info('Getting page %d' % (pages,))
-            if pages == 0 and (time_val or attr_name in ('nsslapd-lookthroughlimit',
-                                                         'nsslapd-pagesizelimit')):
-                rtype, rdata, rmsgid, rctrls = topology_st.standalone.result3(msgid)
+            if pages == 0 and (time_val or attr_name == 'nsslapd-pagesizelimit'):
+                rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
             else:
                 with pytest.raises(expected_err):
-                    rtype, rdata, rmsgid, rctrls = topology_st.standalone.result3(msgid)
+                    rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
                     all_results.extend(rdata)
                     pages += 1
                     pctrls = [
@@ -363,28 +398,24 @@ def test_search_limits_fail(topology_st, test_user, page_size, users_num,
                 if pctrls[0].cookie:
                     # Copy cookie from response control to request control
                     req_ctrl.cookie = pctrls[0].cookie
-                    msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                              ldap.SCOPE_SUBTREE,
-                                                              search_flt,
-                                                              searchreq_attrlist,
-                                                              serverctrls=controls)
+                    msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                            search_flt, searchreq_attrlist, serverctrls=controls)
                 else:
                     break  # No more pages available
             else:
                 break
     finally:
-        log.info('Set Directory Manager bind back (test_search_limits_fail)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
+        del_users(users_list)
         change_conf_attr(topology_st, suffix, attr_name, attr_value_bck)
 
 
-def test_search_sort_success(topology_st, test_user):
+def test_search_sort_success(topology_st, create_user):
     """Verify that search with a simple paged results control
     and a server side sort control returns all entries
     it should without errors.
 
     :id: 17d8b150-ed43-41e1-b80f-ee9b4ce45155
+    :customerscenario: True
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
     :steps:
@@ -403,8 +434,7 @@ def test_search_sort_success(topology_st, test_user):
     searchreq_attrlist = ['dn', 'sn']
 
     try:
-        log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         sort_ctrl = SSSRequestControl(True, ['sn'])
@@ -412,25 +442,25 @@ def test_search_sort_success(topology_st, test_user):
         log.info('Initiate ldapsearch with created control instance')
         log.info('Collect data with sorting')
         controls = [req_ctrl, sort_ctrl]
-        results_sorted = paged_search(topology_st, DEFAULT_SUFFIX, controls,
+        results_sorted = paged_search(conn, DEFAULT_SUFFIX, controls,
                                       search_flt, searchreq_attrlist)
 
         log.info('Substring numbers from user DNs')
-        r_nums = map(lambda x: int(x[0][8:13]), results_sorted)
+        # r_nums = map(lambda x: int(x[0][8:13]), results_sorted)
+        r_nums = [int(x[0][8:13]) for x in results_sorted]
 
         log.info('Assert that list is sorted')
         assert all(r_nums[i] <= r_nums[i + 1] for i in range(len(r_nums) - 1))
     finally:
-        log.info('Set Directory Manager bind back (test_search_sort_success)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
+        del_users(users_list)
 
 
-def test_search_abandon(topology_st, test_user):
+def test_search_abandon(topology_st, create_user):
     """Verify that search with simple paged results control
     can be abandon
 
     :id: 0008538b-7585-4356-839f-268828066978
+    :customerscenario: True
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
     :steps:
@@ -452,36 +482,32 @@ def test_search_abandon(topology_st, test_user):
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         log.info('Create simple paged results control instance')
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         controls = [req_ctrl]
 
         log.info('Initiate a search with a paged results control')
-        msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                  ldap.SCOPE_SUBTREE,
-                                                  search_flt,
-                                                  searchreq_attrlist,
-                                                  serverctrls=controls)
+        msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                search_flt, searchreq_attrlist, serverctrls=controls)
         log.info('Abandon the search')
-        topology_st.standalone.abandon(msgid)
+        conn.abandon(msgid)
 
         log.info('Expect an ldap.TIMEOUT exception, while trying to get the search results')
         with pytest.raises(ldap.TIMEOUT):
-            topology_st.standalone.result3(msgid, timeout=5)
+            conn.result3(msgid, timeout=5)
     finally:
-        log.info('Set Directory Manager bind back (test_search_abandon)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
+        del_users(users_list)
 
 
-def test_search_with_timelimit(topology_st, test_user):
+def test_search_with_timelimit(topology_st, create_user):
     """Verify that after performing multiple simple paged searches
     to completion, each with a timelimit, it wouldn't fail, if we sleep
     for a time more than the timelimit.
 
     :id: 6cd7234b-136c-419f-bf3e-43aa73592cff
+    :customerscenario: True
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
     :steps:
@@ -506,7 +532,7 @@ def test_search_with_timelimit(topology_st, test_user):
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         log.info('Create simple paged results control instance')
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
@@ -514,18 +540,14 @@ def test_search_with_timelimit(topology_st, test_user):
 
         for ii in range(3):
             log.info('Iteration %d' % ii)
-            msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                      ldap.SCOPE_SUBTREE,
-                                                      search_flt,
-                                                      searchreq_attrlist,
-                                                      serverctrls=controls,
-                                                      timeout=timelimit)
+            msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, search_flt,
+                                    searchreq_attrlist, serverctrls=controls, timeout=timelimit)
 
             pages = 0
             pctrls = []
             while True:
                 log.info('Getting page %d' % (pages,))
-                rtype, rdata, rmsgid, rctrls = topology_st.standalone.result3(msgid)
+                rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
                 pages += 1
                 pctrls = [
                     c
@@ -537,12 +559,8 @@ def test_search_with_timelimit(topology_st, test_user):
                     if pctrls[0].cookie:
                         # Copy cookie from response control to request control
                         req_ctrl.cookie = pctrls[0].cookie
-                        msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                                  ldap.SCOPE_SUBTREE,
-                                                                  search_flt,
-                                                                  searchreq_attrlist,
-                                                                  serverctrls=controls,
-                                                                  timeout=timelimit)
+                        msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, search_flt,
+                                                searchreq_attrlist, serverctrls=controls, timeout=timelimit)
                     else:
                         log.info('Done with this search - sleeping %d seconds' % (
                             timelimit * 2))
@@ -551,24 +569,21 @@ def test_search_with_timelimit(topology_st, test_user):
                 else:
                     break
     finally:
-        log.info('Set Directory Manager bind back (test_search_with_timelimit)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
+        del_users(users_list)
 
 
-@pytest.mark.parametrize('aci_subject',
-                         ('dns = "localhost.localdomain"',
-                          'ip = "::1" or ip = "127.0.0.1"'))
-def test_search_dns_ip_aci(topology_st, test_user, aci_subject):
+def test_search_ip_aci(topology_st, create_user):
     """Verify that after performing multiple simple paged searches
     to completion on the suffix with DNS or IP based ACI
 
     :id: bbfddc46-a8c8-49ae-8c90-7265d05b22a9
+    :customerscenario: True
+    :parametrized: yes
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
     :steps:
         1. Back up and remove all previous ACI from suffix
-        2. Add an anonymous ACI for DNS check
+        2. Add an anonymous ACI for IP check
         3. Bind as test user
         4. Search through added users with a simple paged control
         5. Perform steps 4 three times in a row
@@ -584,32 +599,31 @@ def test_search_dns_ip_aci(topology_st, test_user, aci_subject):
         6. ACI should be successfully returned
         7. Results should be the same with ACI with IP subject dn
     """
-
-    users_num = 100
+    users_num = 20
     page_size = 5
     users_list = add_users(topology_st, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
+    log.info("test_search_dns_ip_aci: HOSTNAME: " + HOSTNAME)
+    log.info("test_search_dns_ip_aci: IP_ADDRESS: " + IP_ADDRESS)
+
     try:
         log.info('Back up current suffix ACI')
         acis_bck = topology_st.standalone.aci.list(DEFAULT_SUFFIX, ldap.SCOPE_BASE)
 
         log.info('Add test ACI')
+        bind_rule = 'ip = "{}" or ip = "::1" or ip = "{}"'.format(IP_ADDRESS, OLD_IP_ADDRESS)
         ACI_TARGET = '(targetattr != "userPassword")'
         ACI_ALLOW = '(version 3.0;acl "Anonymous access within domain"; allow (read,compare,search)'
-        ACI_SUBJECT = '(userdn = "ldap:///anyone") and (%s);)' % aci_subject
-        ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
-        try:
-            topology_st.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_REPLACE,
-                                                              'aci',
-                                                              ACI_BODY)])
-        except ldap.LDAPError as e:
-            log.fatal('Failed to add ACI: error (%s)' % (e.message['desc']))
-            raise e
+        ACI_SUBJECT = '(userdn = "ldap:///anyone") and (%s);)' % bind_rule
+        ACI_BODY = ensure_bytes(ACI_TARGET + ACI_ALLOW + ACI_SUBJECT)
+        topology_st.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_REPLACE, 'aci', ACI_BODY)])
+        time.sleep(.5)
 
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        myuri = 'ldap://%s:%d' % (HOSTNAME, topology_st.standalone.port)
+        conn = create_user.bind(TEST_USER_PWD, uri=myuri)
 
         log.info('Create simple paged results control instance')
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
@@ -618,31 +632,27 @@ def test_search_dns_ip_aci(topology_st, test_user, aci_subject):
         log.info('Initiate three searches with a paged results control')
         for ii in range(3):
             log.info('%d search' % (ii + 1))
-            all_results = paged_search(topology_st, DEFAULT_SUFFIX, controls,
+            all_results = paged_search(conn, DEFAULT_SUFFIX, controls,
                                        search_flt, searchreq_attrlist)
             log.info('%d results' % len(all_results))
             assert len(all_results) == len(users_list)
         log.info('If we are here, then no error has happened. We are good.')
 
     finally:
-        log.info('Set Directory Manager bind back (test_search_dns_ip_aci)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
         log.info('Restore ACI')
-        topology_st.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_DELETE,
-                                                          'aci',
-                                                          None)])
+        topology_st.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_DELETE, 'aci', None)])
         for aci in acis_bck:
-            topology_st.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_ADD,
-                                                              'aci',
-                                                              aci.getRawAci())])
-        del_users(topology_st, users_list)
+            topology_st.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_ADD, 'aci', aci.getRawAci())])
+        time.sleep(1)
+        del_users(users_list)
 
 
-def test_search_multiple_paging(topology_st, test_user):
+def test_search_multiple_paging(topology_st, create_user):
     """Verify that after performing multiple simple paged searches
     on a single connection without a complition, it wouldn't fail.
 
     :id: 628b29a6-2d47-4116-a88d-00b87405ef7f
+    :customerscenario: True
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
     :steps:
@@ -657,15 +667,15 @@ def test_search_multiple_paging(topology_st, test_user):
         4. No error happens
     """
 
-    users_num = 100
-    page_size = 30
+    users_num = 20
+    page_size = 5
     users_list = add_users(topology_st, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         log.info('Create simple paged results control instance')
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
@@ -673,12 +683,9 @@ def test_search_multiple_paging(topology_st, test_user):
 
         for ii in range(3):
             log.info('Iteration %d' % ii)
-            msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                      ldap.SCOPE_SUBTREE,
-                                                      search_flt,
-                                                      searchreq_attrlist,
-                                                      serverctrls=controls)
-            rtype, rdata, rmsgid, rctrls = topology_st.standalone.result3(msgid)
+            msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                    search_flt, searchreq_attrlist, serverctrls=controls)
+            rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
             pctrls = [
                 c
                 for c in rctrls
@@ -687,24 +694,21 @@ def test_search_multiple_paging(topology_st, test_user):
 
             # Copy cookie from response control to request control
             req_ctrl.cookie = pctrls[0].cookie
-            msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                      ldap.SCOPE_SUBTREE,
-                                                      search_flt,
-                                                      searchreq_attrlist,
-                                                      serverctrls=controls)
+            msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                    search_flt, searchreq_attrlist, serverctrls=controls)
     finally:
-        log.info('Set Directory Manager bind back (test_search_multiple_paging)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
+        del_users(users_list)
 
 
 @pytest.mark.parametrize("invalid_cookie", [1000, -1])
-def test_search_invalid_cookie(topology_st, test_user, invalid_cookie):
+def test_search_invalid_cookie(topology_st, create_user, invalid_cookie):
     """Verify that using invalid cookie while performing
     search with the simple paged results control throws
     a TypeError exception
 
     :id: 107be12d-4fe4-47fe-ae86-f3e340a56f42
+    :customerscenario: True
+    :parametrized: yes
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
     :steps:
@@ -719,47 +723,40 @@ def test_search_invalid_cookie(topology_st, test_user, invalid_cookie):
         4. It should throw a TypeError exception
     """
 
-    users_num = 100
-    page_size = 50
+    users_num = 20
+    page_size = 5
     users_list = add_users(topology_st, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         log.info('Create simple paged results control instance')
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         controls = [req_ctrl]
 
-        msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                  ldap.SCOPE_SUBTREE,
-                                                  search_flt,
-                                                  searchreq_attrlist,
-                                                  serverctrls=controls)
-        rtype, rdata, rmsgid, rctrls = topology_st.standalone.result3(msgid)
+        msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                search_flt, searchreq_attrlist, serverctrls=controls)
+        rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
 
         log.info('Put an invalid cookie (%d) to the control. TypeError is expected' %
                  invalid_cookie)
         req_ctrl.cookie = invalid_cookie
         with pytest.raises(TypeError):
-            msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                      ldap.SCOPE_SUBTREE,
-                                                      search_flt,
-                                                      searchreq_attrlist,
-                                                      serverctrls=controls)
+            msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                    search_flt, searchreq_attrlist, serverctrls=controls)
     finally:
-        log.info('Set Directory Manager bind back (test_search_invalid_cookie)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
+        del_users(users_list)
 
 
-def test_search_abandon_with_zero_size(topology_st, test_user):
+def test_search_abandon_with_zero_size(topology_st, create_user):
     """Verify that search with simple paged results control
     can be abandon using page_size = 0
 
     :id: d2fd9a10-84e1-4b69-a8a7-36ca1427c171
+    :customerscenario: True
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
     :steps:
@@ -779,18 +776,15 @@ def test_search_abandon_with_zero_size(topology_st, test_user):
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         log.info('Create simple paged results control instance')
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         controls = [req_ctrl]
 
-        msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                  ldap.SCOPE_SUBTREE,
-                                                  search_flt,
-                                                  searchreq_attrlist,
-                                                  serverctrls=controls)
-        rtype, rdata, rmsgid, rctrls = topology_st.standalone.result3(msgid)
+        msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                search_flt, searchreq_attrlist, serverctrls=controls)
+        rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
         pctrls = [
             c
             for c in rctrls
@@ -798,17 +792,16 @@ def test_search_abandon_with_zero_size(topology_st, test_user):
             ]
         assert not pctrls[0].cookie
     finally:
-        log.info('Set Directory Manager bind back (test_search_abandon_with_zero_size)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
+        del_users(users_list)
 
 
-def test_search_pagedsizelimit_success(topology_st, test_user):
+def test_search_pagedsizelimit_success(topology_st, create_user):
     """Verify that search with a simple paged results control
     returns all entries it should without errors while
     valid value set to nsslapd-pagedsizelimit.
 
     :id: 88193f10-f6f0-42f5-ae9c-ff34b8f9ee8c
+    :customerscenario: True
     :setup: Standalone instance, test user for binding,
             10 users for the search base
     :steps:
@@ -826,42 +819,39 @@ def test_search_pagedsizelimit_success(topology_st, test_user):
     page_size = 10
     attr_name = 'nsslapd-pagedsizelimit'
     attr_value = '20'
-    attr_value_bck = change_conf_attr(topology_st, DN_CONFIG,
-                                      attr_name, attr_value)
+    attr_value_bck = change_conf_attr(topology_st, DN_CONFIG, attr_name, attr_value)
     users_list = add_users(topology_st, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         controls = [req_ctrl]
 
-        all_results = paged_search(topology_st, DEFAULT_SUFFIX, controls,
-                                   search_flt, searchreq_attrlist)
+        all_results = paged_search(conn, DEFAULT_SUFFIX, controls, search_flt, searchreq_attrlist)
 
         log.info('%d results' % len(all_results))
         assert len(all_results) == len(users_list)
 
     finally:
-        log.info('Set Directory Manager bind back (test_search_pagedsizelimit_success)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
-        change_conf_attr(topology_st, DN_CONFIG,
-                         'nsslapd-pagedsizelimit', attr_value_bck)
+        del_users(users_list)
+        change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-pagedsizelimit', attr_value_bck)
 
 
 @pytest.mark.parametrize('conf_attr,user_attr,expected_rs',
                          (('5', '15', 'PASS'), ('15', '5', ldap.SIZELIMIT_EXCEEDED)))
-def test_search_nspagedsizelimit(topology_st, test_user,
+def test_search_nspagedsizelimit(topology_st, create_user,
                                  conf_attr, user_attr, expected_rs):
     """Verify that nsPagedSizeLimit attribute overrides
     nsslapd-pagedsizelimit while performing search with
     the simple paged results control.
 
     :id: b08c6ad2-ba28-447a-9f04-5377c3661d0d
+    :customerscenario: True
+    :parametrized: yes
     :setup: Standalone instance, test user for binding,
             10 users for the search base
     :steps:
@@ -895,14 +885,12 @@ def test_search_nspagedsizelimit(topology_st, test_user,
     users_list = add_users(topology_st, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
-    conf_attr_bck = change_conf_attr(topology_st, DN_CONFIG,
-                                     'nsslapd-pagedsizelimit', conf_attr)
-    user_attr_bck = change_conf_attr(topology_st, TEST_USER_DN,
-                                     'nsPagedSizeLimit', user_attr)
+    conf_attr_bck = change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-pagedsizelimit', conf_attr)
+    user_attr_bck = change_conf_attr(topology_st, create_user.dn, 'nsPagedSizeLimit', user_attr)
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         controls = [req_ctrl]
@@ -910,34 +898,30 @@ def test_search_nspagedsizelimit(topology_st, test_user,
         if expected_rs == ldap.SIZELIMIT_EXCEEDED:
             log.info('Expect to fail with SIZELIMIT_EXCEEDED')
             with pytest.raises(expected_rs):
-                all_results = paged_search(topology_st, DEFAULT_SUFFIX, controls,
-                                           search_flt, searchreq_attrlist)
+                all_results = paged_search(conn, DEFAULT_SUFFIX, controls, search_flt, searchreq_attrlist)
         elif expected_rs == 'PASS':
             log.info('Expect to pass')
-            all_results = paged_search(topology_st, DEFAULT_SUFFIX, controls,
-                                       search_flt, searchreq_attrlist)
+            all_results = paged_search(conn, DEFAULT_SUFFIX, controls, search_flt, searchreq_attrlist)
             log.info('%d results' % len(all_results))
             assert len(all_results) == len(users_list)
 
     finally:
-        log.info('Set Directory Manager bind back (test_search_nspagedsizelimit)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
-        change_conf_attr(topology_st, DN_CONFIG,
-                         'nsslapd-pagedsizelimit', conf_attr_bck)
-        change_conf_attr(topology_st, TEST_USER_DN,
-                         'nsPagedSizeLimit', user_attr_bck)
+        del_users(users_list)
+        change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-pagedsizelimit', conf_attr_bck)
+        change_conf_attr(topology_st, create_user.dn, 'nsPagedSizeLimit', user_attr_bck)
 
 
 @pytest.mark.parametrize('conf_attr_values,expected_rs',
                          ((('5000', '100', '100'), ldap.ADMINLIMIT_EXCEEDED),
                           (('5000', '120', '122'), 'PASS')))
-def test_search_paged_limits(topology_st, test_user, conf_attr_values, expected_rs):
+def test_search_paged_limits(topology_st, create_user, conf_attr_values, expected_rs):
     """Verify that nsslapd-idlistscanlimit and
     nsslapd-lookthroughlimit can limit the administrator
     search abilities.
 
     :id: e0f8b916-7276-4bd3-9e73-8696a4468811
+    :customerscenario: True
+    :parametrized: yes
     :setup: Standalone instance, test user for binding,
             10 users for the search base
     :steps:
@@ -972,18 +956,14 @@ def test_search_paged_limits(topology_st, test_user, conf_attr_values, expected_
     users_list = add_users(topology_st, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
-    size_attr_bck = change_conf_attr(topology_st, DN_CONFIG,
-                                     'nsslapd-sizelimit', conf_attr_values[0])
-    pagedsize_attr_bck = change_conf_attr(topology_st, DN_CONFIG,
-                                          'nsslapd-pagedsizelimit', conf_attr_values[0])
-    idlistscan_attr_bck = change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM,
-                                           'nsslapd-idlistscanlimit', conf_attr_values[1])
-    lookthrough_attr_bck = change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM,
-                                            'nsslapd-lookthroughlimit', conf_attr_values[2])
+    size_attr_bck = change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-sizelimit', conf_attr_values[0])
+    pagedsize_attr_bck = change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-pagedsizelimit', conf_attr_values[0])
+    idlistscan_attr_bck = change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM, 'nsslapd-idlistscanlimit', conf_attr_values[1])
+    lookthrough_attr_bck = change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM, 'nsslapd-lookthroughlimit', conf_attr_values[2])
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         controls = [req_ctrl]
@@ -991,37 +971,31 @@ def test_search_paged_limits(topology_st, test_user, conf_attr_values, expected_
         if expected_rs == ldap.ADMINLIMIT_EXCEEDED:
             log.info('Expect to fail with ADMINLIMIT_EXCEEDED')
             with pytest.raises(expected_rs):
-                all_results = paged_search(topology_st, DEFAULT_SUFFIX, controls,
-                                           search_flt, searchreq_attrlist)
+                all_results = paged_search(conn, DEFAULT_SUFFIX, controls, search_flt, searchreq_attrlist)
         elif expected_rs == 'PASS':
             log.info('Expect to pass')
-            all_results = paged_search(topology_st, DEFAULT_SUFFIX, controls,
-                                       search_flt, searchreq_attrlist)
+            all_results = paged_search(conn, DEFAULT_SUFFIX, controls, search_flt, searchreq_attrlist)
             log.info('%d results' % len(all_results))
             assert len(all_results) == len(users_list)
     finally:
-        log.info('Set Directory Manager bind back (test_search_paged_limits)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
-        change_conf_attr(topology_st, DN_CONFIG,
-                         'nsslapd-sizelimit', size_attr_bck)
-        change_conf_attr(topology_st, DN_CONFIG,
-                         'nsslapd-pagedsizelimit', pagedsize_attr_bck)
-        change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM,
-                         'nsslapd-lookthroughlimit', lookthrough_attr_bck)
-        change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM,
-                         'nsslapd-idlistscanlimit', idlistscan_attr_bck)
+        del_users(users_list)
+        change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-sizelimit', size_attr_bck)
+        change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-pagedsizelimit', pagedsize_attr_bck)
+        change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM, 'nsslapd-lookthroughlimit', lookthrough_attr_bck)
+        change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM, 'nsslapd-idlistscanlimit', idlistscan_attr_bck)
 
 
 @pytest.mark.parametrize('conf_attr_values,expected_rs',
                          ((('1000', '100', '100'), ldap.ADMINLIMIT_EXCEEDED),
                           (('1000', '120', '122'), 'PASS')))
-def test_search_paged_user_limits(topology_st, test_user, conf_attr_values, expected_rs):
+def test_search_paged_user_limits(topology_st, create_user, conf_attr_values, expected_rs):
     """Verify that nsPagedIDListScanLimit and nsPagedLookthroughLimit
     override nsslapd-idlistscanlimit and nsslapd-lookthroughlimit
     while performing search with the simple paged results control.
 
     :id: 69e393e9-1ab8-4f4e-b4a1-06ca63dc7b1b
+    :customerscenario: True
+    :parametrized: yes
     :setup: Standalone instance, test user for binding,
             10 users for the search base
     :steps:
@@ -1057,18 +1031,14 @@ def test_search_paged_user_limits(topology_st, test_user, conf_attr_values, expe
     users_list = add_users(topology_st, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
-    lookthrough_attr_bck = change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM,
-                                            'nsslapd-lookthroughlimit', conf_attr_values[0])
-    idlistscan_attr_bck = change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM,
-                                           'nsslapd-idlistscanlimit', conf_attr_values[0])
-    user_idlistscan_attr_bck = change_conf_attr(topology_st, TEST_USER_DN,
-                                                'nsPagedIDListScanLimit', conf_attr_values[1])
-    user_lookthrough_attr_bck = change_conf_attr(topology_st, TEST_USER_DN,
-                                                 'nsPagedLookthroughLimit', conf_attr_values[2])
+    lookthrough_attr_bck = change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM, 'nsslapd-lookthroughlimit', conf_attr_values[0])
+    idlistscan_attr_bck = change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM, 'nsslapd-idlistscanlimit', conf_attr_values[0])
+    user_idlistscan_attr_bck = change_conf_attr(topology_st, create_user.dn, 'nsPagedIDListScanLimit', conf_attr_values[1])
+    user_lookthrough_attr_bck = change_conf_attr(topology_st, create_user.dn, 'nsPagedLookthroughLimit', conf_attr_values[2])
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         controls = [req_ctrl]
@@ -1076,34 +1046,27 @@ def test_search_paged_user_limits(topology_st, test_user, conf_attr_values, expe
         if expected_rs == ldap.ADMINLIMIT_EXCEEDED:
             log.info('Expect to fail with ADMINLIMIT_EXCEEDED')
             with pytest.raises(expected_rs):
-                all_results = paged_search(topology_st, DEFAULT_SUFFIX, controls,
-                                           search_flt, searchreq_attrlist)
+                all_results = paged_search(conn, DEFAULT_SUFFIX, controls, search_flt, searchreq_attrlist)
         elif expected_rs == 'PASS':
             log.info('Expect to pass')
-            all_results = paged_search(topology_st, DEFAULT_SUFFIX, controls,
-                                       search_flt, searchreq_attrlist)
+            all_results = paged_search(conn, DEFAULT_SUFFIX, controls, search_flt, searchreq_attrlist)
             log.info('%d results' % len(all_results))
             assert len(all_results) == len(users_list)
     finally:
-        log.info('Set Directory Manager bind back (test_search_paged_user_limits)')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
-        change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM,
-                         'nsslapd-lookthroughlimit', lookthrough_attr_bck)
-        change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM,
-                         'nsslapd-idlistscanlimit', idlistscan_attr_bck)
-        change_conf_attr(topology_st, TEST_USER_DN,
-                         'nsPagedIDListScanLimit', user_idlistscan_attr_bck)
-        change_conf_attr(topology_st, TEST_USER_DN,
-                         'nsPagedLookthroughLimit', user_lookthrough_attr_bck)
-
-
-def test_ger_basic(topology_st, test_user):
+        del_users(users_list)
+        change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM, 'nsslapd-lookthroughlimit', lookthrough_attr_bck)
+        change_conf_attr(topology_st, 'cn=config,%s' % DN_LDBM, 'nsslapd-idlistscanlimit', idlistscan_attr_bck)
+        change_conf_attr(topology_st, create_user.dn, 'nsPagedIDListScanLimit', user_idlistscan_attr_bck)
+        change_conf_attr(topology_st, create_user.dn, 'nsPagedLookthroughLimit', user_lookthrough_attr_bck)
+
+
+def test_ger_basic(topology_st, create_user):
     """Verify that search with a simple paged results control
     and get effective rights control returns all entries
     it should without errors.
 
     :id: 7b0bdfc7-a2f2-4c1a-bcab-f1eb8b330d45
+    :customerscenario: True
     :setup: Standalone instance, test user for binding,
             varying number of users for the search base
     :steps:
@@ -1120,13 +1083,10 @@ def test_ger_basic(topology_st, test_user):
     page_size = 4
 
     try:
-        log.info('Set bind to directory manager')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-
         spr_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
-        ger_ctrl = GetEffectiveRightsControl(True, "dn: " + DN_DM)
+        ger_ctrl = GetEffectiveRightsControl(True, ensure_bytes("dn: " + DN_DM))
 
-        all_results = paged_search(topology_st, DEFAULT_SUFFIX, [spr_ctrl, ger_ctrl],
+        all_results = paged_search(topology_st.standalone, DEFAULT_SUFFIX, [spr_ctrl, ger_ctrl],
                                    search_flt, searchreq_attrlist)
 
         log.info('{} results'.format(len(all_results)))
@@ -1135,14 +1095,15 @@ def test_ger_basic(topology_st, test_user):
         assert all(attrs['attributeLevelRights'][0] for dn, attrs in all_results)
     finally:
         log.info('Remove added users')
-        del_users(topology_st, users_list)
+        del_users(users_list)
 
 
-def test_multi_suffix_search(topology_st, test_user, new_suffixes):
+def test_multi_suffix_search(topology_st, create_user, new_suffixes):
     """Verify that page result search returns empty cookie
     if there is no returned entry.
 
     :id: 9712345b-9e38-4df6-8794-05f12c457d39
+    :customerscenario: True
     :setup: Standalone instance, test user for binding,
             two suffixes with backends, one is inserted into another,
             10 users for the search base within each suffix
@@ -1168,17 +1129,13 @@ def test_multi_suffix_search(topology_st, test_user, new_suffixes):
     log.info('Clear the access log')
     topology_st.standalone.deleteAccessLogs()
 
-    users_list_1 = add_users(topology_st, users_num / 2, NEW_SUFFIX_1)
-    users_list_2 = add_users(topology_st, users_num / 2, NEW_SUFFIX_2)
+    users_list_1 = add_users(topology_st, 10, NEW_SUFFIX_1)
+    users_list_2 = add_users(topology_st, 10, NEW_SUFFIX_2)
 
     try:
-        log.info('Set DM bind')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
 
-        all_results = paged_search(topology_st, NEW_SUFFIX_1, [req_ctrl],
-                                   search_flt, searchreq_attrlist)
+        all_results = paged_search(topology_st.standalone, NEW_SUFFIX_1, [req_ctrl], search_flt, searchreq_attrlist)
 
         log.info('{} results'.format(len(all_results)))
         assert len(all_results) == users_num
@@ -1195,15 +1152,17 @@ def test_multi_suffix_search(topology_st, test_user, new_suffixes):
         assert pr_cookie_list[-1] == -1
     finally:
         log.info('Remove added users')
-        del_users(topology_st, users_list_1)
-        del_users(topology_st, users_list_2)
+        del_users(users_list_1)
+        del_users(users_list_2)
 
 
 @pytest.mark.parametrize('conf_attr_value', (None, '-1', '1000'))
-def test_maxsimplepaged_per_conn_success(topology_st, test_user, conf_attr_value):
+def test_maxsimplepaged_per_conn_success(topology_st, create_user, conf_attr_value):
     """Verify that nsslapd-maxsimplepaged-per-conn acts according design
 
     :id: 192e2f25-04ee-4ff9-9340-d875dcbe8011
+    :customerscenario: True
+    :parametrized: yes
     :setup: Standalone instance, test user for binding,
             20 users for the search base
     :steps:
@@ -1223,35 +1182,32 @@ def test_maxsimplepaged_per_conn_success(topology_st, test_user, conf_attr_value
     searchreq_attrlist = ['dn', 'sn']
     page_size = 4
     if conf_attr_value:
-        max_per_con_bck = change_conf_attr(topology_st, DN_CONFIG,
-                                           'nsslapd-maxsimplepaged-per-conn',
-                                           conf_attr_value)
+        max_per_con_bck = change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-maxsimplepaged-per-conn', conf_attr_value)
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
 
-        all_results = paged_search(topology_st, DEFAULT_SUFFIX, [req_ctrl],
-                                   search_flt, searchreq_attrlist)
+        all_results = paged_search(conn, DEFAULT_SUFFIX, [req_ctrl], search_flt, searchreq_attrlist)
 
         log.info('{} results'.format(len(all_results)))
         assert len(all_results) == len(users_list)
     finally:
         log.info('Remove added users')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
+        del_users(users_list)
         if conf_attr_value:
-            change_conf_attr(topology_st, DN_CONFIG,
-                             'nsslapd-maxsimplepaged-per-conn', max_per_con_bck)
+            change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-maxsimplepaged-per-conn', max_per_con_bck)
 
 
 @pytest.mark.parametrize('conf_attr_value', ('0', '1'))
-def test_maxsimplepaged_per_conn_failure(topology_st, test_user, conf_attr_value):
+def test_maxsimplepaged_per_conn_failure(topology_st, create_user, conf_attr_value):
     """Verify that nsslapd-maxsimplepaged-per-conn acts according design
 
     :id: eb609e63-2829-4331-8439-a35f99694efa
+    :customerscenario: True
+    :parametrized: yes
     :setup: Standalone instance, test user for binding,
             20 users for the search base
     :steps:
@@ -1272,40 +1228,62 @@ def test_maxsimplepaged_per_conn_failure(topology_st, test_user, conf_attr_value
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
     page_size = 4
-    max_per_con_bck = change_conf_attr(topology_st, DN_CONFIG,
-                                       'nsslapd-maxsimplepaged-per-conn',
-                                       conf_attr_value)
+    max_per_con_bck = change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-maxsimplepaged-per-conn', conf_attr_value)
 
     try:
         log.info('Set user bind')
-        topology_st.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+        conn = create_user.bind(TEST_USER_PWD)
 
         log.info('Create simple paged results control instance')
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
 
         with pytest.raises(ldap.UNWILLING_TO_PERFORM):
-            msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                      ldap.SCOPE_SUBTREE,
-                                                      search_flt,
-                                                      searchreq_attrlist,
-                                                      serverctrls=[req_ctrl])
-            rtype, rdata, rmsgid, rctrls = topology_st.standalone.result3(msgid)
+            msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                    search_flt, searchreq_attrlist, serverctrls=[req_ctrl])
+            rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
 
             # If nsslapd-maxsimplepaged-per-conn = 1,
             # it should pass this point, but failed on the next search
             assert conf_attr_value == '1'
-            msgid = topology_st.standalone.search_ext(DEFAULT_SUFFIX,
-                                                      ldap.SCOPE_SUBTREE,
-                                                      search_flt,
-                                                      searchreq_attrlist,
-                                                      serverctrls=[req_ctrl])
-            rtype, rdata, rmsgid, rctrls = topology_st.standalone.result3(msgid)
+            msgid = conn.search_ext(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+                                    search_flt, searchreq_attrlist, serverctrls=[req_ctrl])
+            rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
     finally:
         log.info('Remove added users')
-        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
-        del_users(topology_st, users_list)
-        change_conf_attr(topology_st, DN_CONFIG,
-                         'nsslapd-maxsimplepaged-per-conn', max_per_con_bck)
+        del_users(users_list)
+        change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-maxsimplepaged-per-conn', max_per_con_bck)
+
+
+def test_search_stress_abandon(create_40k_users, create_user):
+    """Verify that search with a simple paged results control
+    returns all entries it should without errors.
+
+    :id: e154b24a-83d6-11ee-90d1-482ae39447e5
+    :customerscenario: True
+    :feature: Simple paged results
+    :setup: Standalone instance, test user for binding,
+            40K  users in a second backend
+    :steps:
+        1. Bind as test user
+        2. Loops a number of times doing:
+                 - search through added users with a simple paged control
+                 - randomly abandoning the search after a few ms.
+    :expectedresults:
+        1. Bind should be successful
+        2. The loop should complete successfully.
+    """
+
+    abandon_rate = 10
+    page_size = 500
+    nbloops = 1000
+    search_flt = r'(uid=*)'
+    searchreq_attrlist = ['dn', 'sn']
+    log.info('Set user bind %s ' % create_user)
+    conn = create_user.bind(TEST_USER_PWD)
+    for idx in range(nbloops):
+        req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
+        # If the issue #5984 is not fixed the server crashs and the paged search fails with ldap.SERVER_DOWN exception
+        paged_search(conn, create_40k_users.suffix, [req_ctrl], search_flt, searchreq_attrlist, abandon_rate=abandon_rate)
 
 
 if __name__ == '__main__':
diff --git a/ldap/servers/slapd/abandon.c b/ldap/servers/slapd/abandon.c
index 3f7bef018..0d16b60e6 100644
--- a/ldap/servers/slapd/abandon.c
+++ b/ldap/servers/slapd/abandon.c
@@ -38,6 +38,12 @@ do_abandon(Slapi_PBlock *pb)
     Connection *pb_conn = NULL;
     Operation *pb_op = NULL;
     Operation *o;
+    /* Keep a copy of some data because o may vanish once conn is unlocked */
+    struct {
+        struct timespec hr_time_end;
+        int nentries;
+        int opid;
+    } o_copy;
 
     slapi_pblock_get(pb, SLAPI_OPERATION, &pb_op);
     slapi_pblock_get(pb, SLAPI_CONNECTION, &pb_conn);
@@ -90,8 +96,12 @@ do_abandon(Slapi_PBlock *pb)
 
     PR_EnterMonitor(pb_conn->c_mutex);
     for (o = pb_conn->c_ops; o != NULL; o = o->o_next) {
-        if (o->o_msgid == id && o != pb_op)
+        if (o->o_msgid == id && o != pb_op) {
+            slapi_operation_time_elapsed(o, &o_copy.hr_time_end);
+            o_copy.nentries = o->o_results.r.r_search.nentries;
+            o_copy.opid = o->o_opid;
             break;
+        }
     }
 
     if (o != NULL) {
@@ -130,7 +140,8 @@ do_abandon(Slapi_PBlock *pb)
         slapi_log_err(SLAPI_LOG_TRACE, "do_abandon", "op not found\n");
     }
 
-    if (0 == pagedresults_free_one_msgid_nolock(pb_conn, id)) {
+    PR_ExitMonitor(pb_conn->c_mutex);
+    if (0 == pagedresults_free_one_msgid(pb_conn, id, pageresult_lock_get_addr(pb_conn))) {
         slapi_log_access(LDAP_DEBUG_STATS, "conn=%" PRIu64
                                            " op=%d ABANDON targetop=Simple Paged Results msgid=%d\n",
                          pb_conn->c_connid, pb_op->o_opid, id);
@@ -143,15 +154,11 @@ do_abandon(Slapi_PBlock *pb)
                                            " targetop=SUPPRESSED-BY-PLUGIN msgid=%d\n",
                          pb_conn->c_connid, pb_op->o_opid, id);
     } else {
-        struct timespec o_hr_time_end;
-        slapi_operation_time_elapsed(o, &o_hr_time_end);
         slapi_log_access(LDAP_DEBUG_STATS, "conn=%" PRIu64 " op=%d ABANDON"
                                            " targetop=%d msgid=%d nentries=%d etime=%" PRId64 ".%010" PRId64 "\n",
-                         pb_conn->c_connid, pb_op->o_opid, o->o_opid, id,
-                         o->o_results.r.r_search.nentries, (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec);
+                         pb_conn->c_connid, pb_op->o_opid, o_copy.opid, id,
+                         o_copy.nentries, (int64_t)o_copy.hr_time_end.tv_sec, (int64_t)o_copy.hr_time_end.tv_nsec);
     }
-
-    PR_ExitMonitor(pb_conn->c_mutex);
     /*
      * Wake up the persistent searches, so they
      * can notice if they've been abandoned.
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index ec316dfb9..80c670d7b 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/ldap/servers/slapd/opshared.c
@@ -889,9 +889,7 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
                     next_be = NULL; /* to break the loop */
                     if (operation->o_status & SLAPI_OP_STATUS_ABANDONED) {
                         /* It turned out this search was abandoned. */
-                        pthread_mutex_lock(pagedresults_mutex);
-                        pagedresults_free_one_msgid_nolock(pb_conn, operation->o_msgid);
-                        pthread_mutex_unlock(pagedresults_mutex);
+                        pagedresults_free_one_msgid(pb_conn, operation->o_msgid, pagedresults_mutex);
                         /* paged-results-request was abandoned; making an empty cookie. */
                         pagedresults_set_response_control(pb, 0, estimate, -1, pr_idx);
                         send_ldap_result(pb, 0, NULL, "Simple Paged Results Search abandoned", 0, NULL);
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
index 8c043f6af..dc9db2c60 100644
--- a/ldap/servers/slapd/pagedresults.c
+++ b/ldap/servers/slapd/pagedresults.c
@@ -34,6 +34,10 @@ pageresult_lock_cleanup()
     slapi_ch_free((void**)&lock_hash);
 }
 
+/* Beware to the lock order with c_mutex:
+ * c_mutex is sometime locked while holding pageresult_lock
+ * ==> Do not lock pageresult_lock when holing c_mutex
+ */
 pthread_mutex_t *
 pageresult_lock_get_addr(Connection *conn)
 {
@@ -350,7 +354,7 @@ pagedresults_free_one(Connection *conn, Operation *op, int index)
  * Used for abandoning - pageresult_lock_get_addr(conn) is already locked in do_abandone.
  */
 int
-pagedresults_free_one_msgid_nolock(Connection *conn, ber_int_t msgid)
+pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, pthread_mutex_t *mutex)
 {
     int rc = -1;
     int i;
@@ -361,6 +365,7 @@ pagedresults_free_one_msgid_nolock(Connection *conn, ber_int_t msgid)
         } else {
             slapi_log_err(SLAPI_LOG_TRACE,
                           "pagedresults_free_one_msgid_nolock", "=> msgid=%d\n", msgid);
+            pthread_mutex_lock(mutex);
             for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) {
                 if (conn->c_pagedresults.prl_list[i].pr_msgid == msgid) {
                     PagedResults *prp = conn->c_pagedresults.prl_list + i;
@@ -375,6 +380,7 @@ pagedresults_free_one_msgid_nolock(Connection *conn, ber_int_t msgid)
                     break;
                 }
             }
+            pthread_mutex_unlock(mutex);
             slapi_log_err(SLAPI_LOG_TRACE,
                           "pagedresults_free_one_msgid_nolock", "<= %d\n", rc);
         }
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index b8f736107..a02605774 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -1525,7 +1525,7 @@ int pagedresults_is_timedout_nolock(Connection *conn);
 int pagedresults_reset_timedout_nolock(Connection *conn);
 int pagedresults_in_use_nolock(Connection *conn);
 int pagedresults_free_one(Connection *conn, Operation *op, int index);
-int pagedresults_free_one_msgid_nolock(Connection *conn, ber_int_t msgid);
+int pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, pthread_mutex_t *mutex);
 int op_is_pagedresults(Operation *op);
 int pagedresults_cleanup_all(Connection *conn, int needlock);
 void op_set_pagedresults(Operation *op);
-- 
2.41.0