diff --git a/CHANGES b/CHANGES
index b67e3dc8cfe90a718c8117af058f973bb4c3b411..08f914b890f4da6642db7bed9050a3f5ac4ede8a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,7 @@ OpenLDAP 2.4.24 Engineering
 	Added slapd-null back-config support (ITS#6624)
 	Added slapd-sql autocommit support (ITS#6612)
 	Added slapd-sql support for long long keys (ITS#6617)
+	Added slapo-sssvlv multiple sorts per connection (ITS#6686)
 	Added contrib/kinit for kerberos tickets
 	Added contrib/noopsrch for entry counting (ITS#6598)
 	Fixed liblber to not close invalid sockets (ITS#6585)
diff --git a/doc/man/man5/slapo-sssvlv.5 b/doc/man/man5/slapo-sssvlv.5
index b994d2299cfb9efb10f332671a7f58f5c263e0d6..8a2ac7601975c1ca6547d3474d1a45acd6512c7d 100644
--- a/doc/man/man5/slapo-sssvlv.5
+++ b/doc/man/man5/slapo-sssvlv.5
@@ -34,6 +34,10 @@ connections. The default is one half of the number of server threads.
 .TP
 .B sssvlv\-maxkeys <num>
 Set the maximum number of keys allowed in a sort request. The default is 5.
+.TP
+.B sssvlv\-maxperconn <num>
+Set the maximum number of concurrent paged search requests per connection. The default is 5. The number of concurrent requests remains limited by
+.B sssvlv-max.
 .SH FILES
 .TP
 ETCDIR/slapd.conf
diff --git a/servers/slapd/overlays/sssvlv.c b/servers/slapd/overlays/sssvlv.c
index f735b72ea00e5bea39427dfbba7d435ba54b030d..a8ded053a03bc445052065707a14c1afa3b557b2 100644
--- a/servers/slapd/overlays/sssvlv.c
+++ b/servers/slapd/overlays/sssvlv.c
@@ -16,7 +16,8 @@
  */
 /* ACKNOWLEDGEMENTS:
  * This work was initially developed by Howard Chu for inclusion in
- * OpenLDAP Software.
+ * OpenLDAP Software. Support for multiple sorts per connection added
+ * by Raphael Ouazana.
  */
 
 #include "portable.h"
@@ -59,6 +60,10 @@
 #define SAFESTR(macro_str, macro_def) ((macro_str) ? (macro_str) : (macro_def))
 
 #define SSSVLV_DEFAULT_MAX_KEYS	5
+#define SSSVLV_DEFAULT_MAX_REQUEST_PER_CONN 5
+
+#define NO_PS_COOKIE (PagedResultsCookie) -1
+#define NO_VC_CONTEXT (unsigned long) -1
 
 typedef struct vlv_ctrl {
 	int vc_before;
@@ -85,6 +90,7 @@ typedef struct sort_ctrl {
 typedef struct sort_node
 {
 	int sn_conn;
+	int sn_session;
 	struct berval sn_dn;
 	struct berval *sn_vals;
 } sort_node;
@@ -94,6 +100,7 @@ typedef struct sssvlv_info
 	int svi_max;	/* max concurrent sorts */
 	int svi_num;	/* current # sorts */
 	int svi_max_keys;	/* max sort keys per request */
+	int svi_max_percon; /* max concurrent sorts per con */
 } sssvlv_info;
 
 typedef struct sort_op
@@ -107,11 +114,13 @@ typedef struct sort_op
 	int so_vlv;
 	int so_vlv_rc;
 	int so_vlv_target;
+	int so_session;
 	unsigned long so_vcontext;
 } sort_op;
 
 /* There is only one conn table for all overlay instances */
-static sort_op **sort_conns;
+/* Each conn can handle one session by context */
+static sort_op ***sort_conns;
 static ldap_pvt_thread_mutex_t sort_conns_mutex;
 static int ov_count;
 static const char *debug_header = "sssvlv";
@@ -155,7 +164,9 @@ static int node_cmp( const void* val1, const void* val2 )
 {
 	sort_node *sn1 = (sort_node *)val1;
 	sort_node *sn2 = (sort_node *)val2;
-	sort_ctrl *sc = sort_conns[sn1->sn_conn]->so_ctrl;
+	assert( sort_conns[sn1->sn_conn] && sort_conns[sn1->sn_conn][sn1->sn_session]
+		&& sort_conns[sn1->sn_conn][sn1->sn_session]->so_ctrl );
+	sort_ctrl *sc = sort_conns[sn1->sn_conn][sn1->sn_session]->so_ctrl;
 	MatchingRule *mr;
 	int i, cmp = 0;
 
@@ -328,21 +339,73 @@ static int pack_sss_response_control(
 	return rs->sr_err;
 }
 
+/* Return the session id or -1 if unknown */
+static int find_session_by_context(
+	int svi_max_percon,
+	int conn_id,
+	unsigned long vc_context,
+	PagedResultsCookie ps_cookie )
+{
+	int sess_id;
+	for(sess_id = 0; sess_id < svi_max_percon; sess_id++) {
+		if( sort_conns[conn_id] && sort_conns[conn_id][sess_id] &&
+		    ( sort_conns[conn_id][sess_id]->so_vcontext == vc_context || 
+                      (PagedResultsCookie) sort_conns[conn_id][sess_id]->so_tree == ps_cookie ) )
+			return sess_id;
+	}
+	return -1;
+}
+
+static int find_next_session(
+	int svi_max_percon,
+	int conn_id )
+{
+	int sess_id;
+	assert(sort_conns[conn_id] != NULL);
+	for(sess_id = 0; sess_id < svi_max_percon; sess_id++) {
+		if(!sort_conns[conn_id][sess_id]) {
+			return sess_id;
+		}
+	}
+	if (sess_id >= svi_max_percon) {
+		return -1;
+	} else {
+		return sess_id;
+	}
+}
+	
 static void free_sort_op( Connection *conn, sort_op *so )
 {
+	int sess_id;
+	PagedResultsCookie ps_cookie = (PagedResultsCookie) so->so_tree;
 	if ( so->so_tree ) {
 		tavl_free( so->so_tree, ch_free );
 		so->so_tree = NULL;
 	}
 
 	ldap_pvt_thread_mutex_lock( &sort_conns_mutex );
-	sort_conns[conn->c_conn_idx] = NULL;
+	sess_id = find_session_by_context( so->so_info->svi_max_percon, conn->c_conn_idx, so->so_vcontext, ps_cookie );
+	sort_conns[conn->c_conn_idx][sess_id] = NULL;
 	so->so_info->svi_num--;
 	ldap_pvt_thread_mutex_unlock( &sort_conns_mutex );
 
 	ch_free( so );
 }
 
+static void free_sort_ops( Connection *conn, sort_op **sos, int svi_max_percon )
+{
+	int sess_id;
+	sort_op *so;
+
+	for( sess_id = 0; sess_id < svi_max_percon ; sess_id++ ) {
+		so = sort_conns[conn->c_conn_idx][sess_id];
+		if ( so ) {
+			free_sort_op( conn, so );
+			sort_conns[conn->c_conn_idx][sess_id] = NULL;
+		}
+	}
+}
+	
 static void send_list(
 	Operation		*op,
 	SlapReply		*rs,
@@ -427,6 +490,7 @@ range_err:
 			sc->sc_nkeys * sizeof(struct berval), op->o_tmpmemctx );
 		sn->sn_vals = (struct berval *)(sn+1);
 		sn->sn_conn = op->o_conn->c_conn_idx;
+		sn->sn_session = find_session_by_context( so->so_info->svi_max_percon, op->o_conn->c_conn_idx, vc->vc_context, NO_PS_COOKIE );
 		sn->sn_vals[0] = bv;
 		for (i=1; i<sc->sc_nkeys; i++) {
 			BER_BVZERO( &sn->sn_vals[i] );
@@ -665,6 +729,7 @@ static int sssvlv_op_response(
 		op->o_tmpfree( sn, op->o_tmpmemctx );
 		sn = sn2;
 		sn->sn_conn = op->o_conn->c_conn_idx;
+		sn->sn_session = find_session_by_context( so->so_info->svi_max_percon, op->o_conn->c_conn_idx, so->so_vcontext, (PagedResultsCookie) so->so_tree );
 
 		/* Insert into the AVL tree */
 		tavl_insert(&(so->so_tree), sn, node_insert, avl_dup_error);
@@ -700,10 +765,11 @@ static int sssvlv_op_search(
 	sssvlv_info				*si			= on->on_bi.bi_private;
 	int						rc			= SLAP_CB_CONTINUE;
 	int	ok;
-	sort_op *so, so2;
+	sort_op *so = NULL, so2;
 	sort_ctrl *sc;
 	PagedResultsState *ps;
 	vlv_ctrl *vc;
+	int sess_id;
 
 	if ( op->o_ctrlflag[sss_cid] <= SLAP_CONTROL_IGNORED ) {
 		if ( op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ) {
@@ -712,6 +778,7 @@ static int sssvlv_op_search(
 			so2.so_vlv_target = 0;
 			so2.so_nentries = 0;
 			so2.so_vlv_rc = LDAP_VLV_SSS_MISSING;
+			so2.so_vlv = op->o_ctrlflag[vlv_cid];
 			rc = pack_vlv_response_control( op, rs, &so2, ctrls );
 			if ( rc == LDAP_SUCCESS ) {
 				ctrls[1] = NULL;
@@ -750,9 +817,10 @@ static int sssvlv_op_search(
 
 	ok = 1;
 	ldap_pvt_thread_mutex_lock( &sort_conns_mutex );
-	so = sort_conns[op->o_conn->c_conn_idx];
 	/* Is there already a sort running on this conn? */
-	if ( so ) {
+	sess_id = find_session_by_context( si->svi_max_percon, op->o_conn->c_conn_idx, vc ? vc->vc_context : NO_VC_CONTEXT, ps ? ps->ps_cookie : NO_PS_COOKIE );
+	if ( sess_id >= 0 ) {
+		so = sort_conns[op->o_conn->c_conn_idx][sess_id];
 		/* Is it a continuation of a VLV search? */
 		if ( !vc || so->so_vlv <= SLAP_CONTROL_IGNORED ||
 			vc->vc_context != so->so_vcontext ) {
@@ -777,21 +845,24 @@ static int sssvlv_op_search(
 	/* Are there too many running overall? */
 	} else if ( si->svi_num >= si->svi_max ) {
 		ok = 0;
+	} else if ( ( sess_id = find_next_session(si->svi_max_percon, op->o_conn->c_conn_idx ) ) < 0 ) {
+		ok = 0;
 	} else {
 		/* OK, this connection now has a sort running */
 		si->svi_num++;
-		sort_conns[op->o_conn->c_conn_idx] = &so2;
+		sort_conns[op->o_conn->c_conn_idx][sess_id] = &so2;
+		sort_conns[op->o_conn->c_conn_idx][sess_id]->so_session = sess_id;
 	}
 	ldap_pvt_thread_mutex_unlock( &sort_conns_mutex );
 	if ( ok ) {
 		/* are we continuing a VLV search? */
-		if ( vc && vc->vc_context ) {
+		if ( so && vc && vc->vc_context ) {
 			so->so_ctrl = sc;
 			send_list( op, rs, so );
 			send_result( op, rs, so );
 			rc = LDAP_SUCCESS;
 		/* are we continuing a paged search? */
-		} else if ( ps && ps->ps_cookie ) {
+		} else if ( so && ps && ps->ps_cookie ) {
 			so->so_ctrl = sc;
 			send_page( op, rs, so );
 			send_result( op, rs, so );
@@ -805,7 +876,7 @@ static int sssvlv_op_search(
 			} else {
 				so = op->o_tmpcalloc( 1, sizeof(sort_op), op->o_tmpmemctx );
 			}
-			sort_conns[op->o_conn->c_conn_idx] = so;
+			sort_conns[op->o_conn->c_conn_idx][sess_id] = so;
 
 			cb->sc_cleanup		= NULL;
 			cb->sc_response		= sssvlv_op_response;
@@ -830,6 +901,8 @@ static int sssvlv_op_search(
 					so->so_vlv = SLAP_CONTROL_NONE;
 				}
 			}
+			so->so_session = sess_id;
+			so->so_vlv = op->o_ctrlflag[vlv_cid];
 			so->so_vcontext = (unsigned long)so;
 			so->so_nentries = 0;
 
@@ -1099,8 +1172,12 @@ static int vlv_parseCtrl(
 
 static int sssvlv_connection_destroy( BackendDB *be, Connection *conn )
 {
-	if ( sort_conns[conn->c_conn_idx] )
-		free_sort_op( conn, sort_conns[conn->c_conn_idx] );
+	slap_overinst	*on		= (slap_overinst *)be->bd_info;
+	sssvlv_info *si = on->on_bi.bi_private;
+
+	if ( sort_conns[conn->c_conn_idx] ) {
+		free_sort_ops( conn, sort_conns[conn->c_conn_idx], si->svi_max_percon );
+	}
 
 	return LDAP_SUCCESS;
 }
@@ -1112,11 +1189,22 @@ static int sssvlv_db_open(
 	slap_overinst	*on = (slap_overinst *)be->bd_info;
 	sssvlv_info *si = on->on_bi.bi_private;
 	int rc;
+	int conn_index;
 
 	/* If not set, default to 1/2 of available threads */
 	if ( !si->svi_max )
 		si->svi_max = connection_pool_max / 2;
 
+	if ( dtblsize && !sort_conns ) {
+		ldap_pvt_thread_mutex_init( &sort_conns_mutex );
+		/* accommodate for c_conn_idx == -1 */
+		sort_conns = ch_calloc( dtblsize + 1, sizeof(sort_op **) );
+		for ( conn_index = 0 ; conn_index < dtblsize + 1 ; conn_index++ ) {
+			sort_conns[conn_index] = ch_calloc( si->svi_max_percon, sizeof(sort_op *) );
+		}
+		sort_conns++;
+	}
+
 	rc = overlay_register_control( be, LDAP_CONTROL_SORTREQUEST );
 	if ( rc == LDAP_SUCCESS )
 		rc = overlay_register_control( be, LDAP_CONTROL_VLVREQUEST );
@@ -1136,6 +1224,12 @@ static ConfigTable sssvlv_cfg[] = {
 		"( OLcfgOvAt:21.2 NAME 'olcSssVlvMaxKeys' "
 			"DESC 'Maximum number of Keys in a Sort request' "
 			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+	{ "sssvlv-maxpercon", "num",
+		2, 2, 0, ARG_INT|ARG_OFFSET,
+			(void *)offsetof(sssvlv_info, svi_max_percon),
+		"( OLcfgOvAt:21.3 NAME 'olcSssVlvMaxPerConn' "
+			"DESC 'Maximum number of concurrent paged search requests per connection' "
+			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
 };
 
@@ -1194,13 +1288,8 @@ static int sssvlv_db_init(
 	si->svi_max = 0;
 	si->svi_num = 0;
 	si->svi_max_keys = SSSVLV_DEFAULT_MAX_KEYS;
+	si->svi_max_percon = SSSVLV_DEFAULT_MAX_REQUEST_PER_CONN;
 
-	if ( dtblsize && !sort_conns ) {
-		ldap_pvt_thread_mutex_init( &sort_conns_mutex );
-		/* accommodate for c_conn_idx == -1 */
-		sort_conns = ch_calloc( sizeof(sort_op *), dtblsize + 1 );
-		sort_conns++;
-	}
 	ov_count++;
 
 	return LDAP_SUCCESS;
@@ -1212,10 +1301,14 @@ static int sssvlv_db_destroy(
 {
 	slap_overinst	*on = (slap_overinst *)be->bd_info;
 	sssvlv_info *si = (sssvlv_info *)on->on_bi.bi_private;
+	int conn_index;
 	
 	ov_count--;
 	if ( !ov_count && sort_conns) {
 		sort_conns--;
+		for ( conn_index = 0 ; conn_index < dtblsize + 1 ; conn_index++ ) {
+			ch_free(sort_conns[conn_index]);
+		}
 		ch_free(sort_conns);
 		ldap_pvt_thread_mutex_destroy( &sort_conns_mutex );
 	}