diff --git a/servers/slapd/back-monitor/back-monitor.h b/servers/slapd/back-monitor/back-monitor.h
index cddd899abc4ec5b9ebc7aa0713e959d72cc61896..e9e8df1006c220fef76a5f95f7d6a62c70048561 100644
--- a/servers/slapd/back-monitor/back-monitor.h
+++ b/servers/slapd/back-monitor/back-monitor.h
@@ -103,6 +103,7 @@ struct monitorinfo {
 	AttributeDescription *mi_ad_seeAlso;
 	AttributeDescription *mi_ad_l;
 	AttributeDescription *mi_ad_labeledURI;
+	AttributeDescription *mi_ad_readOnly;
 };
 
 /*
diff --git a/servers/slapd/back-monitor/database.c b/servers/slapd/back-monitor/database.c
index 7191e5479b43efefe69d745a31faafa5d8bdc504..b754376c334685c424bf284831f7f5b2525cae9e 100644
--- a/servers/slapd/back-monitor/database.c
+++ b/servers/slapd/back-monitor/database.c
@@ -45,6 +45,7 @@ monitor_subsys_database_init(
 	Entry			*e, *e_database, *e_tmp;
 	int			i;
 	struct monitorentrypriv	*mp;
+	struct berval *tf;
 
 	assert( be != NULL );
 
@@ -67,6 +68,9 @@ monitor_subsys_database_init(
 #endif
 		return( -1 );
 	}
+	tf = (global_restrictops & SLAP_RESTRICT_OP_WRITES) ?
+		(struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv ; 
+	attr_merge_one( e_database, mi->mi_ad_readOnly, tf, tf );
 
 	e_tmp = NULL;
 	for ( i = nBackendDB; i--; ) {
@@ -137,6 +141,9 @@ monitor_subsys_database_init(
 			attr_merge( e_database, slap_schema.si_ad_namingContexts,
 					be->be_suffix, be->be_nsuffix );
 		}
+		tf = (be->be_restrictops & SLAP_RESTRICT_OP_WRITES) ?
+			(struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv ; 
+		attr_merge_one( e, mi->mi_ad_readOnly, tf, tf );
 
 		if ( oi != NULL ) {
 			slap_overinst *on = oi->oi_list;
@@ -236,6 +243,120 @@ monitor_subsys_database_init(
 	return( 0 );
 }
 
+int
+monitor_subsys_database_modify(
+	Operation	*op,
+	Entry		*e
+)
+{
+	struct monitorinfo *mi = (struct monitorinfo *)op->o_bd->be_private;
+	int rc = LDAP_OTHER;
+	Attribute *save_attrs;
+	Modifications *modlist = op->oq_modify.rs_modlist;
+	Modifications *ml;
+	Backend *be;
+	int gotval = 1, i, n, cur;
+	
+	i = sscanf( e->e_nname.bv_val, "cn=database %d,", &n );
+	if ( i != 1 )
+		return LDAP_UNWILLING_TO_PERFORM;
+
+	if ( n < 0 || n >= nBackendDB )
+		return LDAP_NO_SUCH_OBJECT;
+
+	be = &backendDB[n];
+	cur = (be->be_restrictops & SLAP_RESTRICT_OP_WRITES) ? 1 : 0;
+
+	save_attrs = e->e_attrs;
+	e->e_attrs = attrs_dup( e->e_attrs );
+
+	for ( ml=modlist; ml; ml=ml->sml_next ) {
+		Modification *mod = &ml->sml_mod;
+
+		if ( mod->sm_desc == mi->mi_ad_readOnly ) {
+			int val = -1;
+
+			if ( mod->sm_values ) {
+				/* single-valued */
+				if ( !BER_BVISNULL(&mod->sm_values[1]) ) {
+					rc = LDAP_CONSTRAINT_VIOLATION;
+					break;
+				}
+				if ( bvmatch( &slap_true_bv, mod->sm_values )) {
+					val = 1;
+				} else if ( bvmatch( &slap_false_bv, mod->sm_values )) {
+					val = 0;
+				}
+			}
+			switch( mod->sm_op ) {
+			case LDAP_MOD_DELETE:
+				if ( val < 0 || val == cur ) {
+					gotval--;
+					cur = -1;
+				} else {
+					rc = LDAP_NO_SUCH_ATTRIBUTE;
+				}
+				break;
+			case LDAP_MOD_REPLACE:
+				gotval--;
+				cur = -1;
+				/* FALLTHRU */
+			case LDAP_MOD_ADD:
+				if ( val < 0 ) {
+					rc = LDAP_INVALID_SYNTAX;
+				} else {
+					gotval++;
+					cur = val;
+				}
+				break;
+			default:
+				rc = LDAP_OTHER;
+				break;
+			}
+			if ( rc ) {
+				break;
+			}
+		} else if ( is_at_operational( mod->sm_desc->ad_type )) {
+		/* accept all operational attributes */
+			attr_delete( &e->e_attrs, mod->sm_desc );
+			rc = attr_merge( e, mod->sm_desc, mod->sm_values,
+				mod->sm_nvalues );
+			if ( rc ) {
+				rc = LDAP_OTHER;
+				break;
+			}
+		} else {
+			rc = LDAP_UNWILLING_TO_PERFORM;
+			break;
+		}
+	}
+	if ( gotval == 1 && cur >= 0 ) {
+		struct berval *tf;
+		tf = cur ? (struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv;
+		attr_delete( &e->e_attrs, mi->mi_ad_readOnly );
+		rc = attr_merge_one( e, mi->mi_ad_readOnly, tf, tf );
+		if ( rc == LDAP_SUCCESS ) {
+			if ( cur ) {
+				be->be_restrictops |= SLAP_RESTRICT_OP_WRITES;
+			} else {
+				be->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
+			}
+		} else {
+			rc = LDAP_OTHER;
+		}
+	} else {
+		rc = LDAP_CONSTRAINT_VIOLATION;
+	}
+	if ( rc == LDAP_SUCCESS ) {
+		attrs_free( save_attrs );
+	} else {
+		Attribute *tmp = e->e_attrs;
+		e->e_attrs = save_attrs;
+		attrs_free( tmp );
+	}
+	return rc;
+}
+
 #if defined(LDAP_SLAPI)
 static int
 monitor_back_add_plugin( Backend *be, Entry *e_database )
diff --git a/servers/slapd/back-monitor/init.c b/servers/slapd/back-monitor/init.c
index 6173c12949a43fa90a258415105a776ffc32eed1..5ed5b01bb31713623cd04bd5ddb7871b11887a8f 100644
--- a/servers/slapd/back-monitor/init.c
+++ b/servers/slapd/back-monitor/init.c
@@ -55,7 +55,7 @@ struct monitorsubsys monitor_subsys[] = {
 		monitor_subsys_database_init,
 		NULL,   /* update */
 		NULL,   /* create */
-		NULL	/* modify */
+		monitor_subsys_database_modify
        	}, { 
 		SLAPD_MONITOR_BACKEND, SLAPD_MONITOR_BACKEND_NAME, 
 		BER_BVNULL, BER_BVNULL, BER_BVNULL,
@@ -457,6 +457,14 @@ monitor_back_db_open(
 			"NO-USER-MODIFICATION "
 			"USAGE directoryOperation )", SLAP_AT_HIDE,
 			offsetof(struct monitorinfo, mi_ad_monitorOverlay) },
+		{ "readOnly", "( 1.3.6.1.4.1.4203.666.1.31 "
+			"NAME 'readOnly' "
+			"DESC 'read/write status of a given database' "
+			"EQUALITY booleanMatch "
+			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
+			"SINGLE-VALUE "
+			"USAGE directoryOperation )", SLAP_AT_HIDE,
+			offsetof(struct monitorinfo, mi_ad_readOnly) },
 #ifdef INTEGRATE_CORE_SCHEMA
 		{ NULL, NULL, 0, -1 },	/* description */
 		{ NULL, NULL, 0, -1 },	/* seeAlso */
diff --git a/servers/slapd/back-monitor/proto-back-monitor.h b/servers/slapd/back-monitor/proto-back-monitor.h
index 9b5980174bab47f264e6d2487a533978da240e7f..072504e59bd9adb54887eba7e666206c9a47fd7a 100644
--- a/servers/slapd/back-monitor/proto-back-monitor.h
+++ b/servers/slapd/back-monitor/proto-back-monitor.h
@@ -41,6 +41,7 @@ int monitor_subsys_backend_init LDAP_P(( BackendDB *be ));
  * databases 
  */
 int monitor_subsys_database_init LDAP_P(( BackendDB *be ));
+int monitor_subsys_database_modify LDAP_P(( Operation *op, Entry *e ));
 
 /*
  * threads