diff --git a/CHANGES b/CHANGES
index 317533e3fc83946d3a441ff3bdaa93b30e329e97..96047ce9dfd908aafad7204fa50c869db1015b73 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,7 @@ OpenLDAP 2.4 Change Log
 
 OpenLDAP 2.4.22 Engineering
 	Added slapd SLAP_SCHEMA_EXPOSE flag for hidden schema elements (ITS#6435)
+	Added slapd tools selective iterations (ITS#6442)
 	Added slapo-pbind
 	Fixed libldap GnuTLS serial length (ITS#6460)
 	Fixed slapd certificateListValidate (ITS#6466)
diff --git a/doc/devel/toolargs b/doc/devel/toolargs
index 995e70c5e729c1f163cc9567bd1623b1c9bed605..eae05c953e58dad8618b336ac17974acdfd0664c 100644
--- a/doc/devel/toolargs
+++ b/doc/devel/toolargs
@@ -2,11 +2,11 @@ Tools           ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
 slapacl            D F              U  X   b d f        o     uv
 slapadd              F            S        bcd fg  j l no q s uvw
 slapauth             F      M    R  U  X     d f        o      v
-slapcat              F                    abcd fg    l no   s  v
+slapcat              F H                  abcd fg    l no   s  v
 slapdn               F       N P             d f        o      v
 slapindex            F                     bcd fg      no q  t v
 slappasswd                         T        c    h          s uv
-slapschema	     F                    abcd fg    l no   s  v
+slapschema	     F H                  abcd fg    l no   s  v
 slaptest             F          Q            d f       no     uv
 
 * General flags:
diff --git a/doc/man/man8/slapcat.8 b/doc/man/man8/slapcat.8
index e6c81897537896c0380b60653250db8ab152260c..4673e49118529f42f6aced4d5655b1cf1774151c 100644
--- a/doc/man/man8/slapcat.8
+++ b/doc/man/man8/slapcat.8
@@ -21,6 +21,8 @@ slapcat \- SLAPD database to LDIF utility
 [\c
 .BR \-g ]
 [\c
+.BI \-H URI\fR]
+[\c
 .BI \-l ldif-file\fR]
 [\c
 .BI \-n dbnum\fR]
@@ -69,6 +71,7 @@ slapcat \-a \\
 
 will dump all but the "ou=People,dc=example,dc=com" subtree
 of the "dc=example,dc=com" database.
+Deprecated; use \fB-H\fP \fIldap:///???(filter)\fP instead.
 .TP
 .BI \-b \ suffix 
 Use the specified \fIsuffix\fR to determine which database to
@@ -109,6 +112,9 @@ default config file is ignored.
 disable subordinate gluing.  Only the specified database will be
 processed, and not its glued subordinates (if any).
 .TP
+.B \-H \ URI
+use dn, scope and filter from URI to only handle matching entries.
+.TP
 .BI \-l \ ldif-file
 Write LDIF to specified file instead of standard output.
 .TP
@@ -147,6 +153,7 @@ Implies \fB\-b\fP \fIsubtree-dn\fP if no
 or
 .B \-n
 option is given.
+Deprecated; use \fB-H\fP \fIldap:///subtree-dn\fP instead.
 .TP
 .B \-v
 Enable verbose mode.
diff --git a/doc/man/man8/slapschema.8 b/doc/man/man8/slapschema.8
index 5d89919b4c1691834bcc64017f7357f1e4237e63..72a4624084896183c72efce5025edfe2b956d845 100644
--- a/doc/man/man8/slapschema.8
+++ b/doc/man/man8/slapschema.8
@@ -21,6 +21,8 @@ slapschema \- SLAPD in-database schema checking utility
 [\c
 .BR \-g ]
 [\c
+.BI \-H URI\fR]
+[\c
 .BI \-l error-file\fR]
 [\c
 .BI \-n dbnum\fR]
@@ -72,6 +74,7 @@ slapschema \-a \\
 
 will check all but the "ou=People,dc=example,dc=com" subtree
 of the "dc=example,dc=com" database.
+Deprecated; use \fB-H\fP \fIldap:///???(filter)\fP instead.
 .TP
 .BI \-b \ suffix 
 Use the specified \fIsuffix\fR to determine which database to
@@ -112,6 +115,9 @@ default config file is ignored.
 disable subordinate gluing.  Only the specified database will be
 processed, and not its glued subordinates (if any).
 .TP
+.B \-H \ URI
+use dn, scope and filter from URI to only handle matching entries.
+.TP
 .BI \-l \ error-file
 Write errors to specified file instead of standard output.
 .TP
@@ -149,6 +155,7 @@ Implies \fB\-b\fP \fIsubtree-dn\fP if no
 nor
 .B \-n
 option is given.
+Deprecated; use \fB-H\fP \fIldap:///subtree-dn\fP instead.
 .TP
 .B \-v
 Enable verbose mode.
diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c
index e824caea5fdd458c86640445dc78bc76ffa67d0c..9bb102404fb92c3f08851f5dde3b064dc5aba276 100644
--- a/servers/slapd/back-bdb/init.c
+++ b/servers/slapd/back-bdb/init.c
@@ -830,7 +830,8 @@ bdb_back_initialize(
 	 */
 	bi->bi_tool_entry_open = bdb_tool_entry_open;
 	bi->bi_tool_entry_close = bdb_tool_entry_close;
-	bi->bi_tool_entry_first = bdb_tool_entry_next;
+	bi->bi_tool_entry_first = backend_tool_entry_first;
+	bi->bi_tool_entry_first_x = bdb_tool_entry_first_x;
 	bi->bi_tool_entry_next = bdb_tool_entry_next;
 	bi->bi_tool_entry_get = bdb_tool_entry_get;
 	bi->bi_tool_entry_put = bdb_tool_entry_put;
diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h
index 278d7503fd0cdabf932569f60665306122afe1d1..72d7f80336bc6b5ccbd1053c9252f5ef358f692f 100644
--- a/servers/slapd/back-bdb/proto-bdb.h
+++ b/servers/slapd/back-bdb/proto-bdb.h
@@ -627,6 +627,7 @@ bdb_trans_backoff( int num_retries );
 #define bdb_hasSubordinates		BDB_SYMBOL(hasSubordinates)
 #define bdb_tool_entry_open		BDB_SYMBOL(tool_entry_open)
 #define bdb_tool_entry_close		BDB_SYMBOL(tool_entry_close)
+#define bdb_tool_entry_first_x		BDB_SYMBOL(tool_entry_first_x)
 #define bdb_tool_entry_next		BDB_SYMBOL(tool_entry_next)
 #define bdb_tool_entry_get		BDB_SYMBOL(tool_entry_get)
 #define bdb_tool_entry_put		BDB_SYMBOL(tool_entry_put)
@@ -657,6 +658,7 @@ extern BI_has_subordinates 		bdb_hasSubordinates;
 /* tools.c */
 extern BI_tool_entry_open		bdb_tool_entry_open;
 extern BI_tool_entry_close		bdb_tool_entry_close;
+extern BI_tool_entry_first_x		bdb_tool_entry_first_x;
 extern BI_tool_entry_next		bdb_tool_entry_next;
 extern BI_tool_entry_get		bdb_tool_entry_get;
 extern BI_tool_entry_put		bdb_tool_entry_put;
diff --git a/servers/slapd/back-bdb/tools.c b/servers/slapd/back-bdb/tools.c
index b6a30dbca8082acc03aaba842c946daf10f6eb3d..3bb4117c575e35f153c04b8c5dd0609618a26e97 100644
--- a/servers/slapd/back-bdb/tools.c
+++ b/servers/slapd/back-bdb/tools.c
@@ -42,6 +42,11 @@ static unsigned nholes;
 
 static int index_nattrs;
 
+static struct berval	*tool_base;
+static int		tool_scope;
+static Filter		*tool_filter;
+static Entry		*tool_next_entry;
+
 #ifdef BDB_TOOL_IDL_CACHING
 #define bdb_tool_idl_cmp		BDB_SYMBOL(tool_idl_cmp)
 #define bdb_tool_idl_flush_one		BDB_SYMBOL(tool_idl_flush_one)
@@ -91,6 +96,9 @@ static void * bdb_tool_trickle_task( void *ctx, void *ptr );
 
 static void * bdb_tool_index_task( void *ctx, void *ptr );
 
+static int
+bdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep );
+
 int bdb_tool_entry_open(
 	BackendDB *be, int mode )
 {
@@ -187,6 +195,20 @@ int bdb_tool_entry_close(
 	return 0;
 }
 
+ID
+bdb_tool_entry_first_x(
+	BackendDB *be,
+	struct berval *base,
+	int scope,
+	Filter *f )
+{
+	tool_base = base;
+	tool_scope = scope;
+	tool_filter = f;
+	
+	return bdb_tool_entry_next( be );
+}
+
 ID bdb_tool_entry_next(
 	BackendDB *be )
 {
@@ -198,6 +220,7 @@ ID bdb_tool_entry_next(
 	assert( slapMode & SLAP_TOOL_MODE );
 	assert( bdb != NULL );
 
+next:;
 	/* Get the header */
 	data.ulen = data.dlen = sizeof( ehbuf );
 	data.data = ehbuf;
@@ -224,6 +247,47 @@ ID bdb_tool_entry_next(
 
 	BDB_DISK2ID( key.data, &id );
 	previd = id;
+
+	if ( tool_filter || tool_base ) {
+		static Operation op = {0};
+		static Opheader ohdr = {0};
+
+		op.o_hdr = &ohdr;
+		op.o_bd = be;
+		op.o_tmpmemctx = NULL;
+		op.o_tmpmfuncs = &ch_mfuncs;
+
+		if ( tool_next_entry ) {
+			bdb_entry_release( &op, tool_next_entry, 0 );
+			tool_next_entry = NULL;
+		}
+
+		rc = bdb_tool_entry_get_int( be, id, &tool_next_entry );
+		if ( rc == LDAP_NO_SUCH_OBJECT ) {
+			goto next;
+		}
+
+		assert( tool_next_entry != NULL );
+
+#ifdef BDB_HIER
+		/* TODO: needed until BDB_HIER is handled accordingly
+		 * in bdb_tool_entry_get_int() */
+		if ( tool_base && !dnIsSuffixScope( &tool_next_entry->e_nname, tool_base, tool_scope ) )
+		{
+			bdb_entry_release( &op, tool_next_entry, 0 );
+			tool_next_entry = NULL;
+			goto next;
+		}
+#endif
+
+		if ( tool_filter && test_filter( NULL, tool_next_entry, tool_filter ) != LDAP_COMPARE_TRUE )
+		{
+			bdb_entry_release( &op, tool_next_entry, 0 );
+			tool_next_entry = NULL;
+			goto next;
+		}
+	}
+
 	return id;
 }
 
@@ -253,7 +317,8 @@ ID bdb_tool_dn2id_get(
 	return ei->bei_id;
 }
 
-Entry* bdb_tool_entry_get( BackendDB *be, ID id )
+static int
+bdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep )
 {
 	Entry *e = NULL;
 	char *dptr;
@@ -262,6 +327,12 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id )
 	assert( be != NULL );
 	assert( slapMode & SLAP_TOOL_MODE );
 
+	if ( ( tool_filter || tool_base ) && id == previd && tool_next_entry != NULL ) {
+		*ep = tool_next_entry;
+		tool_next_entry = NULL;
+		return LDAP_SUCCESS;
+	}
+
 	if ( id != previd ) {
 		data.ulen = data.dlen = sizeof( ehbuf );
 		data.data = ehbuf;
@@ -269,7 +340,10 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id )
 
 		BDB_ID2DISK( id, &nid );
 		rc = cursor->c_get( cursor, &key, &data, DB_SET );
-		if ( rc ) goto done;
+		if ( rc ) {
+			rc = LDAP_OTHER;
+			goto done;
+		}
 	}
 
 	/* Get the header */
@@ -279,13 +353,19 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id )
 	rc = entry_header( &eh );
 	eoff = eh.data - eh.bv.bv_val;
 	eh.bv.bv_val = dptr;
-	if ( rc ) goto done;
+	if ( rc ) {
+		rc = LDAP_OTHER;
+		goto done;
+	}
 
 	/* Get the size */
 	data.flags &= ~DB_DBT_PARTIAL;
 	data.ulen = 0;
-    rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
-	if ( rc != DB_BUFFER_SMALL ) goto done;
+	rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
+	if ( rc != DB_BUFFER_SMALL ) {
+		rc = LDAP_OTHER;
+		goto done;
+	}
 
 	/* Allocate a block and retrieve the data */
 	eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + data.size;
@@ -297,8 +377,23 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id )
 	/* Skip past already parsed nattr/nvals */
 	eh.data += eoff;
 
-    rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
-	if ( rc ) goto done;
+	rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
+	if ( rc ) {
+		rc = LDAP_OTHER;
+		goto done;
+	}
+
+#ifndef BDB_HIER
+	/* TODO: handle BDB_HIER accordingly */
+	if ( tool_base != NULL ) {
+		struct berval ndn;
+		entry_decode_dn( &eh, NULL, &ndn );
+
+		if ( !dnIsSuffixScope( &ndn, tool_base, tool_scope ) ) {
+			return LDAP_NO_SUCH_OBJECT;
+		}
+	}
+#endif
 
 #ifdef SLAP_ZONE_ALLOC
 	/* FIXME: will add ctx later */
@@ -334,7 +429,23 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id )
 #endif
 	}
 done:
-	return e;
+	if ( e != NULL ) {
+		*ep = e;
+	}
+
+	return rc;
+}
+
+Entry*
+bdb_tool_entry_get( BackendDB *be, ID id )
+{
+	Entry *e = NULL;
+	int rc;
+
+	rc = bdb_tool_entry_get_int( be, id, &e );
+	if ( rc == LDAP_SUCCESS ) {
+		return e;
+	}
 }
 
 static int bdb_tool_next_id(
@@ -610,6 +721,9 @@ int bdb_tool_entry_reindex(
 	Operation op = {0};
 	Opheader ohdr = {0};
 
+	assert( tool_base == NULL );
+	assert( tool_filter == NULL );
+
 	Debug( LDAP_DEBUG_ARGS,
 		"=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
 		(long) id, 0, 0 );
diff --git a/servers/slapd/back-ldif/ldif.c b/servers/slapd/back-ldif/ldif.c
index f376e16387b0e01c0f5152becb532303495d9895..6d4cc61030b5210ac124fb0612a473b7efd73171 100644
--- a/servers/slapd/back-ldif/ldif.c
+++ b/servers/slapd/back-ldif/ldif.c
@@ -37,6 +37,9 @@ struct ldif_tool {
 	ID		ecount;				/* number of entries */
 	ID		ecurrent;			/* bi_tool_entry_next() position */
 #	define	ENTRY_BUFF_INCREMENT 500 /* initial entries[] length */
+	struct berval	*tl_base;
+	int		tl_scope;
+	Filter		*tl_filter;
 };
 
 /* Per-database data */
@@ -1581,17 +1584,38 @@ ldif_tool_entry_next( BackendDB *be )
 {
 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
 
-	if ( tl->ecurrent >= tl->ecount )
-		return NOID;
-	else
-		return ++tl->ecurrent;
+	do {
+		Entry *e = tl->entries[ tl->ecurrent ];
+
+		if ( tl->ecurrent >= tl->ecount ) {
+			return NOID;
+		}
+
+		++tl->ecurrent;
+
+		if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) {
+			continue;
+		}
+
+		if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter  ) != LDAP_COMPARE_TRUE ) {
+			continue;
+		}
+
+		break;
+	} while ( 1 );
+
+	return tl->ecurrent;
 }
 
 static ID
-ldif_tool_entry_first( BackendDB *be )
+ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
 {
 	struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool;
 
+	tl->tl_base = base;
+	tl->tl_scope = scope;
+	tl->tl_filter = f;
+
 	if ( tl->entries == NULL ) {
 		Operation op = {0};
 
@@ -1740,7 +1764,8 @@ ldif_back_initialize( BackendInfo *bi )
 
 	bi->bi_tool_entry_open = ldif_tool_entry_open;
 	bi->bi_tool_entry_close = ldif_tool_entry_close;
-	bi->bi_tool_entry_first = ldif_tool_entry_first;
+	bi->bi_tool_entry_first = backend_tool_entry_first;
+	bi->bi_tool_entry_first_x = ldif_tool_entry_first_x;
 	bi->bi_tool_entry_next = ldif_tool_entry_next;
 	bi->bi_tool_entry_get = ldif_tool_entry_get;
 	bi->bi_tool_entry_put = ldif_tool_entry_put;
diff --git a/servers/slapd/back-monitor/init.c b/servers/slapd/back-monitor/init.c
index 33e680e90d001d9c6360074deeeae049d06a9db7..8dc5a429ada8506030b7afc7b94768bca6298b16 100644
--- a/servers/slapd/back-monitor/init.c
+++ b/servers/slapd/back-monitor/init.c
@@ -2061,6 +2061,7 @@ monitor_back_initialize(
 	bi->bi_tool_entry_open = 0;
 	bi->bi_tool_entry_close = 0;
 	bi->bi_tool_entry_first = 0;
+	bi->bi_tool_entry_first_x = 0;
 	bi->bi_tool_entry_next = 0;
 	bi->bi_tool_entry_get = 0;
 	bi->bi_tool_entry_put = 0;
diff --git a/servers/slapd/back-null/null.c b/servers/slapd/back-null/null.c
index 7df6cf907d6211e3356adfdd1efd42428d4449be..dca92ac2494de1bb92fedbd4f1e159654c922407 100644
--- a/servers/slapd/back-null/null.c
+++ b/servers/slapd/back-null/null.c
@@ -254,6 +254,12 @@ null_tool_entry_close( BackendDB *be )
 	return 0;
 }
 
+static ID
+null_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f )
+{
+	return NOID;
+}
+
 static ID
 null_tool_entry_next( BackendDB *be )
 {
@@ -392,7 +398,8 @@ null_back_initialize( BackendInfo *bi )
 
 	bi->bi_tool_entry_open = null_tool_entry_open;
 	bi->bi_tool_entry_close = null_tool_entry_close;
-	bi->bi_tool_entry_first = null_tool_entry_next;
+	bi->bi_tool_entry_first = backend_tool_entry_first;
+	bi->bi_tool_entry_first_x = null_tool_entry_first_x;
 	bi->bi_tool_entry_next = null_tool_entry_next;
 	bi->bi_tool_entry_get = null_tool_entry_get;
 	bi->bi_tool_entry_put = null_tool_entry_put;
diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c
index fd03b845c08d2ecd6582eb05dbe32a3e100150fa..6c197c09544c2cf4685192ca71050a3fc15d4edf 100644
--- a/servers/slapd/backend.c
+++ b/servers/slapd/backend.c
@@ -1965,3 +1965,12 @@ int backend_operational( Operation *op, SlapReply *rs )
 	return rc;
 }
 
+/* helper that calls the bi_tool_entry_first_x() variant with default args;
+ * use to initialize a backend's bi_tool_entry_first() when appropriate
+ */
+ID
+backend_tool_entry_first( BackendDB *be )
+{
+	return be->bd_info->bi_tool_entry_first_x( be,
+		NULL, LDAP_SCOPE_DEFAULT, NULL );
+}
diff --git a/servers/slapd/backglue.c b/servers/slapd/backglue.c
index cc104ce3ca762eefc9d8e34462a78b879a13ecb1..e37176f5ad4fc7a44e2309dd827716d814a8e139 100644
--- a/servers/slapd/backglue.c
+++ b/servers/slapd/backglue.c
@@ -735,6 +735,10 @@ glue_entry_release_rw (
 	return rc;
 }
 
+static struct berval *glue_base;
+static int glue_scope;
+static Filter *glue_filter;
+
 static ID
 glue_tool_entry_first (
 	BackendDB *b0
@@ -785,6 +789,66 @@ glue_tool_entry_first (
 	return rc;
 }
 
+static ID
+glue_tool_entry_first_x (
+	BackendDB *b0,
+	struct berval *base,
+	int scope,
+	Filter *f
+)
+{
+	slap_overinst	*on = glue_tool_inst( b0->bd_info );
+	glueinfo		*gi = on->on_bi.bi_private;
+	int i;
+	ID rc;
+
+	glue_base = base;
+	glue_scope = scope;
+	glue_filter = f;
+
+	/* If we're starting from scratch, start at the most general */
+	if (!glueBack) {
+		if ( toolDB.be_entry_open && toolDB.be_entry_first_x ) {
+			glueBack = &toolDB;
+		} else {
+			for (i = gi->gi_nodes-1; i >= 0; i--) {
+				if (gi->gi_n[i].gn_be->be_entry_open &&
+					gi->gi_n[i].gn_be->be_entry_first_x)
+				{
+					glueBack = gi->gi_n[i].gn_be;
+					break;
+				}
+			}
+		}
+	}
+	if (!glueBack || !glueBack->be_entry_open || !glueBack->be_entry_first_x ||
+		glueBack->be_entry_open (glueBack, glueMode) != 0)
+		return NOID;
+
+	rc = glueBack->be_entry_first_x (glueBack,
+		glue_base, glue_scope, glue_filter);
+	while ( rc == NOID ) {
+		if ( glueBack && glueBack->be_entry_close )
+			glueBack->be_entry_close (glueBack);
+		for (i=0; i<gi->gi_nodes; i++) {
+			if (gi->gi_n[i].gn_be == glueBack)
+				break;
+		}
+		if (i == 0) {
+			glueBack = GLUEBACK_DONE;
+			break;
+		} else {
+			glueBack = gi->gi_n[i-1].gn_be;
+			rc = glue_tool_entry_first_x (b0,
+				glue_base, glue_scope, glue_filter);
+			if ( glueBack == GLUEBACK_DONE ) {
+				break;
+			}
+		}
+	}
+	return rc;
+}
+
 static ID
 glue_tool_entry_next (
 	BackendDB *b0
@@ -813,7 +877,15 @@ glue_tool_entry_next (
 			break;
 		} else {
 			glueBack = gi->gi_n[i-1].gn_be;
-			rc = glue_tool_entry_first (b0);
+			if ( glue_base || glue_filter ) {
+				/* using entry_first_x() */
+				rc = glue_tool_entry_first_x (b0,
+					glue_base, glue_scope, glue_filter);
+
+			} else {
+				/* using entry_first() */
+				rc = glue_tool_entry_first (b0);
+			}
 			if ( glueBack == GLUEBACK_DONE ) {
 				break;
 			}
@@ -1012,6 +1084,9 @@ glue_db_init(
 		oi->oi_bi.bi_tool_entry_close = glue_tool_entry_close;
 	if ( bi->bi_tool_entry_first )
 		oi->oi_bi.bi_tool_entry_first = glue_tool_entry_first;
+	/* FIXME: check whether all support bi_tool_entry_first_x() ? */
+	if ( bi->bi_tool_entry_first_x )
+		oi->oi_bi.bi_tool_entry_first_x = glue_tool_entry_first_x;
 	if ( bi->bi_tool_entry_next )
 		oi->oi_bi.bi_tool_entry_next = glue_tool_entry_next;
 	if ( bi->bi_tool_entry_get )
diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c
index 027cc2a6448d94c1273e56c13c5c68f10fe52680..8626f2170377329d1a4e3c9c1323a2e774412922 100644
--- a/servers/slapd/bconfig.c
+++ b/servers/slapd/bconfig.c
@@ -6789,10 +6789,30 @@ config_tool_entry_first( BackendDB *be )
 	CfBackInfo *cfb = be->be_private;
 	BackendInfo *bi = cfb->cb_db.bd_info;
 
-	if ( bi && bi->bi_tool_entry_first )
+	if ( bi && bi->bi_tool_entry_first ) {
 		return bi->bi_tool_entry_first( &cfb->cb_db );
-	else
-		return NOID;
+	}
+	if ( bi && bi->bi_tool_entry_first_x ) {
+		return bi->bi_tool_entry_first_x( &cfb->cb_db,
+			NULL, LDAP_SCOPE_DEFAULT, NULL );
+	}
+	return NOID;
+}
+
+static ID
+config_tool_entry_first_x(
+	BackendDB *be,
+	struct berval *base,
+	int scope,
+	Filter *f )
+{
+	CfBackInfo *cfb = be->be_private;
+	BackendInfo *bi = cfb->cb_db.bd_info;
+
+	if ( bi && bi->bi_tool_entry_first_x ) {
+		return bi->bi_tool_entry_first_x( &cfb->cb_db, base, scope, f );
+	}
+	return NOID;
 }
 
 static ID
@@ -7039,6 +7059,7 @@ config_back_initialize( BackendInfo *bi )
 	bi->bi_tool_entry_open = config_tool_entry_open;
 	bi->bi_tool_entry_close = config_tool_entry_close;
 	bi->bi_tool_entry_first = config_tool_entry_first;
+	bi->bi_tool_entry_first_x = config_tool_entry_first_x;
 	bi->bi_tool_entry_next = config_tool_entry_next;
 	bi->bi_tool_entry_get = config_tool_entry_get;
 	bi->bi_tool_entry_put = config_tool_entry_put;
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index 8bf3580084afdc7febf55f54602804c65276f6d3..e27c119c67b3c3fee7956dbe3459df3a01c8a222 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -428,6 +428,8 @@ LDAP_SLAPD_F (int) backend_operational LDAP_P((
 	SlapReply *rs 
 ));
 
+LDAP_SLAPD_F (ID) backend_tool_entry_first LDAP_P(( BackendDB *be ));
+
 LDAP_SLAPD_V(BackendInfo) slap_binfo[]; 
 
 /*
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index a02991cd419b33de40998a8582a5e2d4c54ef9b2..b8147826091f9aca6b555614c25e590d7644aa26 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -1788,6 +1788,7 @@ struct BackendDB {
 #define		be_entry_open bd_info->bi_tool_entry_open
 #define		be_entry_close bd_info->bi_tool_entry_close
 #define		be_entry_first bd_info->bi_tool_entry_first
+#define		be_entry_first_x bd_info->bi_tool_entry_first_x
 #define		be_entry_next bd_info->bi_tool_entry_next
 #define		be_entry_reindex bd_info->bi_tool_entry_reindex
 #define		be_entry_get bd_info->bi_tool_entry_get
@@ -2158,6 +2159,7 @@ typedef BI_conn_func BI_connection_destroy;
 typedef int (BI_tool_entry_open) LDAP_P(( BackendDB *be, int mode ));
 typedef int (BI_tool_entry_close) LDAP_P(( BackendDB *be ));
 typedef ID (BI_tool_entry_first) LDAP_P(( BackendDB *be ));
+typedef ID (BI_tool_entry_first_x) LDAP_P(( BackendDB *be, struct berval *base, int scope, Filter *f ));
 typedef ID (BI_tool_entry_next) LDAP_P(( BackendDB *be ));
 typedef Entry* (BI_tool_entry_get) LDAP_P(( BackendDB *be, ID id ));
 typedef ID (BI_tool_entry_put) LDAP_P(( BackendDB *be, Entry *e, 
@@ -2257,7 +2259,8 @@ struct BackendInfo {
 	/* hooks for slap tools */
 	BI_tool_entry_open	*bi_tool_entry_open;
 	BI_tool_entry_close	*bi_tool_entry_close;
-	BI_tool_entry_first	*bi_tool_entry_first;
+	BI_tool_entry_first	*bi_tool_entry_first;	/* deprecated */
+	BI_tool_entry_first_x	*bi_tool_entry_first_x;
 	BI_tool_entry_next	*bi_tool_entry_next;
 	BI_tool_entry_get	*bi_tool_entry_get;
 	BI_tool_entry_put	*bi_tool_entry_put;
diff --git a/servers/slapd/slapcat.c b/servers/slapd/slapcat.c
index 98364969f6c7695258908c2fe4e36dfeefa66d2c..af1cae4993e4f17c6d4703ffc382c0659ceaea56 100644
--- a/servers/slapd/slapcat.c
+++ b/servers/slapd/slapcat.c
@@ -47,9 +47,13 @@ slapcat( int argc, char **argv )
 	int rc = EXIT_SUCCESS;
 	Operation op = {0};
 	const char *progname = "slapcat";
+	int requestBSF;
+	int doBSF = 0;
 
 	slap_tool_init( progname, SLAPCAT, argc, argv );
 
+	requestBSF = ( sub_ndn.bv_len || filter );
+
 #ifdef SIGPIPE
 	(void) SIGNAL( SIGPIPE, slapcat_sig );
 #endif
@@ -61,7 +65,7 @@ slapcat( int argc, char **argv )
 
 	if( !be->be_entry_open ||
 		!be->be_entry_close ||
-		!be->be_entry_first ||
+		!( be->be_entry_first_x || be->be_entry_first ) ||
 		!be->be_entry_next ||
 		!be->be_entry_get )
 	{
@@ -77,9 +81,22 @@ slapcat( int argc, char **argv )
 	}
 
 	op.o_bd = be;
-	for ( id = be->be_entry_first( be );
-		id != NOID;
-		id = be->be_entry_next( be ) )
+	if ( !requestBSF && be->be_entry_first ) {
+		id = be->be_entry_first( be );
+
+	} else {
+		if ( be->be_entry_first_x ) {
+			id = be->be_entry_first_x( be,
+				sub_ndn.bv_len ? &sub_ndn : NULL, scope, filter );
+
+		} else {
+			assert( be->be_entry_first != NULL );
+			doBSF = 1;
+			id = be->be_entry_first( be );
+		}
+	}
+
+	for ( ; id != NOID; id = be->be_entry_next( be ) )
 	{
 		char *data;
 		int len;
@@ -96,20 +113,24 @@ slapcat( int argc, char **argv )
 			break;
 		}
 
-		if( sub_ndn.bv_len && !dnIsSuffix( &e->e_nname, &sub_ndn ) ) {
-			be_entry_release_r( &op, e );
-			continue;
-		}
-
-		if( filter != NULL ) {
-			int rc = test_filter( NULL, e, filter );
-			if( rc != LDAP_COMPARE_TRUE ) {
+		if ( doBSF ) {
+			if ( sub_ndn.bv_len && !dnIsSuffixScope( &e->e_nname, &sub_ndn, scope ) )
+			{
 				be_entry_release_r( &op, e );
 				continue;
 			}
+
+
+			if ( filter != NULL ) {
+				int rc = test_filter( NULL, e, filter );
+				if ( rc != LDAP_COMPARE_TRUE ) {
+					be_entry_release_r( &op, e );
+					continue;
+				}
+			}
 		}
 
-		if( verbose ) {
+		if ( verbose ) {
 			printf( "# id=%08lx\n", (long) id );
 		}
 
diff --git a/servers/slapd/slapcommon.c b/servers/slapd/slapcommon.c
index 71870e745c068a098c9ca2ef9c889c9da0998edb..f4e2eff51ce28df37aca66df7eabc84d63771f38 100644
--- a/servers/slapd/slapcommon.c
+++ b/servers/slapd/slapcommon.c
@@ -80,7 +80,7 @@ usage( int tool, const char *progname )
 
 	case SLAPCAT:
 		options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]"
-			" [-l ldiffile] [-a filter] [-s subtree]\n";
+			" [-l ldiffile] [-a filter] [-s subtree] [-H url]\n";
 		break;
 
 	case SLAPDN:
@@ -97,7 +97,7 @@ usage( int tool, const char *progname )
 
 	case SLAPSCHEMA:
 		options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]"
-			" [-l errorfile] [-a filter] [-s subtree]\n";
+			" [-l errorfile] [-a filter] [-s subtree] [-H url]\n";
 		break;
 	}
 
@@ -247,13 +247,15 @@ slap_tool_init(
 	leakfilename = NULL;
 #endif
 
+	scope = LDAP_SCOPE_DEFAULT;
+
 	switch( tool ) {
 	case SLAPADD:
 		options = "b:cd:f:F:gj:l:n:o:qsS:uvw";
 		break;
 
 	case SLAPCAT:
-		options = "a:b:cd:f:F:gl:n:o:s:v";
+		options = "a:b:cd:f:F:gH:l:n:o:s:v";
 		mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
 		break;
 
@@ -263,7 +265,7 @@ slap_tool_init(
 		break;
 
 	case SLAPSCHEMA:
-		options = "a:b:cd:f:F:gl:n:o:s:v";
+		options = "a:b:cd:f:F:gH:l:n:o:s:v";
 		mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
 		break;
 
@@ -344,6 +346,52 @@ slap_tool_init(
 			use_glue = 0;
 			break;
 
+		case 'H': {
+			LDAPURLDesc *ludp;
+			int rc;
+
+			rc = ldap_url_parse_ext( optarg, &ludp,
+				LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_NOEMPTY_DN );
+			if ( rc != LDAP_URL_SUCCESS ) {
+				usage( tool, progname );
+			}
+
+			/* don't accept host, port, attrs, extensions */
+			if ( ldap_pvt_url_scheme2proto( ludp->lud_scheme ) != LDAP_PROTO_TCP ) {
+				usage( tool, progname );
+			}
+
+			if ( ludp->lud_host != NULL ) {
+				usage( tool, progname );
+			}
+
+			if ( ludp->lud_port != 0 ) {
+				usage( tool, progname );
+			}
+
+			if ( ludp->lud_attrs != NULL ) {
+				usage( tool, progname );
+			}
+
+			if ( ludp->lud_exts != NULL ) {
+				usage( tool, progname );
+			}
+
+			if ( ludp->lud_dn != NULL && ludp->lud_dn[0] != '\0' ) {
+				subtree = ludp->lud_dn;
+				ludp->lud_dn = NULL;
+			}
+
+			if ( ludp->lud_filter != NULL && ludp->lud_filter[0] != '\0' ) {
+				filterstr = ludp->lud_filter;
+				ludp->lud_filter = NULL;
+			}
+
+			scope = ludp->lud_scope;
+
+			ldap_free_urldesc( ludp );
+			} break;
+
 		case 'j':	/* jump to linenumber */
 			if ( lutil_atoi( &jumpline, optarg ) ) {
 				usage( tool, progname );
@@ -743,6 +791,17 @@ get_db:
 		}
 	}
 
+	if ( scope != LDAP_SCOPE_DEFAULT && BER_BVISNULL( &sub_ndn ) ) {
+		if ( be && be->be_nsuffix ) {
+			ber_dupbv( &sub_ndn, be->be_nsuffix );
+
+		} else {
+			fprintf( stderr,
+				"<scope> needs a DN or a valid database\n" );
+			exit( EXIT_FAILURE );
+		}
+	}
+
 startup:;
 	if ( be ) {
 		BackendDB *bdtmp;
@@ -833,3 +892,5 @@ int slap_tool_destroy( void )
 	}
 	return rc;
 }
+
+
diff --git a/servers/slapd/slapcommon.h b/servers/slapd/slapcommon.h
index d354652e26fad6d14da34829cad63342652ff95a..dae63cd012c0cac2c078bcb19b9f2034366a49df 100644
--- a/servers/slapd/slapcommon.h
+++ b/servers/slapd/slapcommon.h
@@ -43,8 +43,9 @@ typedef struct tool_vars {
 	int tv_nosubordinates;
 	int tv_dryrun;
 	int tv_jumpline;
-	Filter *tv_filter;
 	struct berval tv_sub_ndn;
+	int tv_scope;
+	Filter *tv_filter;
 	struct LDIFFP	*tv_ldiffp;
 	struct berval tv_baseDN;
 	struct berval tv_authcDN;
@@ -76,8 +77,9 @@ extern tool_vars tool_globals;
 #define continuemode tool_globals.tv_continuemode
 #define nosubordinates tool_globals.tv_nosubordinates
 #define dryrun tool_globals.tv_dryrun
-#define filter tool_globals.tv_filter
 #define sub_ndn tool_globals.tv_sub_ndn
+#define scope tool_globals.tv_scope
+#define filter tool_globals.tv_filter
 #define ldiffp tool_globals.tv_ldiffp
 #define baseDN tool_globals.tv_baseDN
 #define authcDN tool_globals.tv_authcDN
diff --git a/servers/slapd/slapindex.c b/servers/slapd/slapindex.c
index 2696c6b8e0422e8c28c2d111e2eeb2b11afe4f4f..3698ed0bb513234a52ef665309ad92486ea9d962 100644
--- a/servers/slapd/slapindex.c
+++ b/servers/slapd/slapindex.c
@@ -43,7 +43,7 @@ slapindex( int argc, char **argv )
 
 	if( !be->be_entry_open ||
 		!be->be_entry_close ||
-		!be->be_entry_first ||
+		!( be->be_entry_first || be->be_entry_first_x ) ||
 		!be->be_entry_next  ||
 		!be->be_entry_reindex )
 	{
@@ -77,11 +77,16 @@ slapindex( int argc, char **argv )
 			progname );
 		exit( EXIT_FAILURE );
 	}
-	
-	for ( id = be->be_entry_first( be );
-		id != NOID;
-		id = be->be_entry_next( be ) )
-	{
+
+	if ( be->be_entry_first ) {
+		id = be->be_entry_first( be );
+
+	} else {
+		assert( be->be_entry_first_x != NULL );
+		id = be->be_entry_first_x( be, NULL, LDAP_SCOPE_DEFAULT, NULL );
+	}
+
+	for ( ; id != NOID; id = be->be_entry_next( be ) ) {
 		int rtn;
 
 		if( verbose ) {
diff --git a/servers/slapd/slapschema.c b/servers/slapd/slapschema.c
index a7aa035b6c1975725bb7a9517aec2284253ba82b..8ed4204a16ce8bba5463db9903a1495b85673670 100644
--- a/servers/slapd/slapschema.c
+++ b/servers/slapd/slapschema.c
@@ -50,9 +50,13 @@ slapschema( int argc, char **argv )
 	OperationBuffer	opbuf;
 	Operation *op = NULL;
 	void *thrctx;
+	int requestBSF = 0;
+	int doBSF = 0;
 
 	slap_tool_init( progname, SLAPCAT, argc, argv );
 
+	requestBSF = ( sub_ndn.bv_len || filter );
+
 #ifdef SIGPIPE
 	(void) SIGNAL( SIGPIPE, slapcat_sig );
 #endif
@@ -64,7 +68,7 @@ slapschema( int argc, char **argv )
 
 	if( !be->be_entry_open ||
 		!be->be_entry_close ||
-		!be->be_entry_first ||
+		!( be->be_entry_first || be->be_entry_first_x ) ||
 		!be->be_entry_next ||
 		!be->be_entry_get )
 	{
@@ -85,10 +89,23 @@ slapschema( int argc, char **argv )
 	op->o_tmpmemctx = NULL;
 	op->o_bd = be;
 
-	for ( id = be->be_entry_first( be );
-		id != NOID;
-		id = be->be_entry_next( be ) )
-	{
+
+	if ( !requestBSF && be->be_entry_first ) {
+		id = be->be_entry_first( be );
+
+	} else {
+		if ( be->be_entry_first_x ) {
+			id = be->be_entry_first_x( be,
+				sub_ndn.bv_len ? &sub_ndn : NULL, scope, filter );
+
+		} else {
+			assert( be->be_entry_first != NULL );
+			doBSF = 1;
+			id = be->be_entry_first( be );
+		}
+	}
+
+	for ( ; id != NOID; id = be->be_entry_next( be ) ) {
 		Entry* e;
 		char textbuf[SLAP_TEXT_BUFLEN];
 		size_t textlen = sizeof(textbuf);
@@ -105,17 +122,21 @@ slapschema( int argc, char **argv )
 			break;
 		}
 
-		if( sub_ndn.bv_len && !dnIsSuffix( &e->e_nname, &sub_ndn ) ) {
-			be_entry_release_r( op, e );
-			continue;
-		}
-
-		if( filter != NULL ) {
-			int rc = test_filter( NULL, e, filter );
-			if( rc != LDAP_COMPARE_TRUE ) {
+		if ( doBSF ) {
+			if ( sub_ndn.bv_len && !dnIsSuffixScope( &e->e_nname, &sub_ndn, scope ) )
+			{
 				be_entry_release_r( op, e );
 				continue;
 			}
+
+
+			if ( filter != NULL ) {
+				int rc = test_filter( NULL, e, filter );
+				if ( rc != LDAP_COMPARE_TRUE ) {
+					be_entry_release_r( op, e );
+					continue;
+				}
+			}
 		}
 
 		if( verbose ) {