diff --git a/doc/man/man5/slapo-memberof.5 b/doc/man/man5/slapo-memberof.5
index b9f6e06761bb9d25ffef02873e49c2b579710115..b5cf27d4bc5e1564229457c72c51fdd1f931bd29 100644
--- a/doc/man/man5/slapo-memberof.5
+++ b/doc/man/man5/slapo-memberof.5
@@ -36,59 +36,69 @@ The following
 configuration options are defined for the memberofoverlay.
 
 .TP
-.B memberof-group-oc <group-oc>
+.BI memberof-group-oc \ <group-oc>
 The value 
-.B <group-oc> 
+.I <group-oc> 
 is the name of the objectClass that triggers the reverse group membership
 update.
 It defaults to \fIgroupOfNames\fP.
 
 .TP
-.B memberof-member-ad <member-ad>
+.BI memberof-member-ad \ <member-ad>
 The value 
-.B <member-ad> 
+.I <member-ad> 
 is the name of the attribute that contains the names of the members
 in the group objects; it must be DN-valued.
 It defaults to \fImember\fP.
 
 .TP
-.B memberof-memberof-ad <memberof-ad>
+.BI memberof-memberof-ad \ <memberof-ad>
 The value 
-.B <memberof-ad> 
+.I <memberof-ad> 
 is the name of the attribute that contains the names of the groups
 an entry is member of; it must be DN-valued.  Its contents are 
 automatically updated by the overlay.
 It defaults to \fImemberOf\fP.
 
 .TP
-.B memberof-dn <dn>
+.BI memberof-dn \ <dn>
 The value 
-.B <dn> 
+.I <dn> 
 contains the DN that is used as \fImodifiersName\fP for internal 
 modifications performed to update the reverse group membership.
 It defaults to the \fIrootdn\fP of the underlying database.
 
 .TP
-.B memberof-dangling {ignore, drop, error}
+.BI "memberof-dangling {" ignore ", " drop ", " error "}"
 This option determines the behavior of the overlay when, during 
 a modification, it encounters dangling references.
 The default is
-.BR ignore ,
+.IR ignore ,
 which may leave dangling references.
 Other options are
-.BR drop ,
+.IR drop ,
 which discards those modifications that would result in dangling
 references, and
-.BR error ,
+.IR error ,
 which causes modifications that would result in dangling references
 to fail.
 
 .TP
-.B memberof-refint {true|FALSE}
+.BI memberof-dangling-error \ <error-code>
+If
+.BR memberof-dangling
+is set to
+.IR error ,
+this configuration parameter can be used to modify the response code
+returned in case of violation.  It defaults to "constraint violation",
+but other implementations are known to return "no such object" instead.
+
+.TP
+.BI "memberof-refint {" true "|" FALSE "}"
 This option determines whether the overlay will try to preserve
 referential integrity or not.
 If set to
-.BR TRUE ,
+.IR TRUE ,
 when an entry containing values of the "is member of" attribute is modified,
 the corresponding groups are modified as well.
 
diff --git a/servers/slapd/config.c b/servers/slapd/config.c
index 93fdf1dc5f4ec645f666a75045283db34001fef2..6e20e6a09c28b9f734560bde3165a1a2c07de14b 100644
--- a/servers/slapd/config.c
+++ b/servers/slapd/config.c
@@ -1007,6 +1007,92 @@ enum_to_verb(slap_verbmasks *v, slap_mask_t m, struct berval *bv) {
 	return -1;
 }
 
+static slap_verbmasks slap_ldap_response_code_[] = {
+	{ BER_BVC("success"),				LDAP_SUCCESS },
+
+	{ BER_BVC("operationsError"),			LDAP_OPERATIONS_ERROR },
+	{ BER_BVC("protocolError"),			LDAP_PROTOCOL_ERROR },
+	{ BER_BVC("timelimitExceeded"),			LDAP_TIMELIMIT_EXCEEDED },
+	{ BER_BVC("sizelimitExceeded"),			LDAP_SIZELIMIT_EXCEEDED },
+	{ BER_BVC("compareFalse"),			LDAP_COMPARE_FALSE },
+	{ BER_BVC("compareTrue"),			LDAP_COMPARE_TRUE },
+
+	{ BER_BVC("authMethodNotSupported"),		LDAP_AUTH_METHOD_NOT_SUPPORTED },
+	{ BER_BVC("strongAuthNotSupported"),		LDAP_STRONG_AUTH_NOT_SUPPORTED },
+	{ BER_BVC("strongAuthRequired"),		LDAP_STRONG_AUTH_REQUIRED },
+	{ BER_BVC("strongerAuthRequired"),		LDAP_STRONGER_AUTH_REQUIRED },
+#if 0 /* not LDAPv3 */
+	{ BER_BVC("partialResults"),			LDAP_PARTIAL_RESULTS },
+#endif
+
+	{ BER_BVC("referral"),				LDAP_REFERRAL },
+	{ BER_BVC("adminlimitExceeded"),		LDAP_ADMINLIMIT_EXCEEDED },
+	{ BER_BVC("unavailableCriticalExtension"),	LDAP_UNAVAILABLE_CRITICAL_EXTENSION },
+	{ BER_BVC("confidentialityRequired"),		LDAP_CONFIDENTIALITY_REQUIRED },
+	{ BER_BVC("saslBindInProgress"),		LDAP_SASL_BIND_IN_PROGRESS },
+
+	{ BER_BVC("noSuchAttribute"),			LDAP_NO_SUCH_ATTRIBUTE },
+	{ BER_BVC("undefinedType"),			LDAP_UNDEFINED_TYPE },
+	{ BER_BVC("inappropriateMatching"),		LDAP_INAPPROPRIATE_MATCHING },
+	{ BER_BVC("constraintViolation"),		LDAP_CONSTRAINT_VIOLATION },
+	{ BER_BVC("typeOrValueExists"),			LDAP_TYPE_OR_VALUE_EXISTS },
+	{ BER_BVC("invalidSyntax"),			LDAP_INVALID_SYNTAX },
+
+	{ BER_BVC("noSuchObject"),			LDAP_NO_SUCH_OBJECT },
+	{ BER_BVC("aliasProblem"),			LDAP_ALIAS_PROBLEM },
+	{ BER_BVC("invalidDnSyntax"),			LDAP_INVALID_DN_SYNTAX },
+#if 0 /* not LDAPv3 */
+	{ BER_BVC("isLeaf"),				LDAP_IS_LEAF },
+#endif
+	{ BER_BVC("aliasDerefProblem"),			LDAP_ALIAS_DEREF_PROBLEM },
+
+	{ BER_BVC("proxyAuthzFailure"),			LDAP_X_PROXY_AUTHZ_FAILURE },
+	{ BER_BVC("inappropriateAuth"),			LDAP_INAPPROPRIATE_AUTH },
+	{ BER_BVC("invalidCredentials"),		LDAP_INVALID_CREDENTIALS },
+	{ BER_BVC("insufficientAccess"),		LDAP_INSUFFICIENT_ACCESS },
+
+	{ BER_BVC("busy"),				LDAP_BUSY },
+	{ BER_BVC("unavailable"),			LDAP_UNAVAILABLE },
+	{ BER_BVC("unwillingToPerform"),		LDAP_UNWILLING_TO_PERFORM },
+	{ BER_BVC("loopDetect"),			LDAP_LOOP_DETECT },
+
+	{ BER_BVC("namingViolation"),			LDAP_NAMING_VIOLATION },
+	{ BER_BVC("objectClassViolation"),		LDAP_OBJECT_CLASS_VIOLATION },
+	{ BER_BVC("notAllowedOnNonleaf"),		LDAP_NOT_ALLOWED_ON_NONLEAF },
+	{ BER_BVC("notAllowedOnRdn"),			LDAP_NOT_ALLOWED_ON_RDN },
+	{ BER_BVC("alreadyExists"),			LDAP_ALREADY_EXISTS },
+	{ BER_BVC("noObjectClassMods"),			LDAP_NO_OBJECT_CLASS_MODS },
+	{ BER_BVC("resultsTooLarge"),			LDAP_RESULTS_TOO_LARGE },
+	{ BER_BVC("affectsMultipleDsas"),		LDAP_AFFECTS_MULTIPLE_DSAS },
+
+	{ BER_BVC("other"),				LDAP_OTHER },
+
+	/* extension-specific */
+
+	{ BER_BVC("cupResourcesExhausted"),		LDAP_CUP_RESOURCES_EXHAUSTED },
+	{ BER_BVC("cupSecurityViolation"),		LDAP_CUP_SECURITY_VIOLATION },
+	{ BER_BVC("cupInvalidData"),			LDAP_CUP_INVALID_DATA },
+	{ BER_BVC("cupUnsupportedScheme"),		LDAP_CUP_UNSUPPORTED_SCHEME },
+	{ BER_BVC("cupReloadRequired"),			LDAP_CUP_RELOAD_REQUIRED },
+
+	{ BER_BVC("cancelled"),				LDAP_CANCELLED },
+	{ BER_BVC("noSuchOperation"),			LDAP_NO_SUCH_OPERATION },
+	{ BER_BVC("tooLate"),				LDAP_TOO_LATE },
+	{ BER_BVC("cannotCancel"),			LDAP_CANNOT_CANCEL },
+
+	{ BER_BVC("assertionFailed"),			LDAP_ASSERTION_FAILED },
+
+	{ BER_BVC("proxiedAuthorizationDenied"),	LDAP_PROXIED_AUTHORIZATION_DENIED },
+
+	{ BER_BVC("syncRefreshRequired"),		LDAP_SYNC_REFRESH_REQUIRED },
+
+	{ BER_BVC("noOperation"),			LDAP_X_NO_OPERATION },
+
+	{ BER_BVNULL,				0 }
+};
+
+slap_verbmasks *slap_ldap_response_code = slap_ldap_response_code_;
+
 #ifdef HAVE_TLS
 static slap_verbmasks tlskey[] = {
 	{ BER_BVC("no"),	SB_TLS_OFF },
diff --git a/servers/slapd/config.h b/servers/slapd/config.h
index 5964b8df9af548346aa018c753552080a286db73..c6b97945650862025c0dd8a0ae92623e8f5faff1 100644
--- a/servers/slapd/config.h
+++ b/servers/slapd/config.h
@@ -196,4 +196,6 @@ int config_shadow( ConfigArgs *c, int flag );
 
 #define	SLAP_X_ORDERED_FMT	"{%d}"
 
+extern slap_verbmasks *slap_ldap_response_code;
+
 #endif /* CONFIG_H */
diff --git a/servers/slapd/overlays/memberof.c b/servers/slapd/overlays/memberof.c
index 45c388650d4f8ac67dae28b47df751bd651709f6..df834c88b007a24598d1a3cedabddd1ed8cbbdc8 100644
--- a/servers/slapd/overlays/memberof.c
+++ b/servers/slapd/overlays/memberof.c
@@ -155,6 +155,8 @@ typedef struct memberof_t {
 #define	MEMBEROF_FREFINT	0x04U
 #define	MEMBEROF_FREVERSE	0x08U
 
+	ber_int_t		mo_dangling_err;
+
 #define MEMBEROF_CHK(mo,f) \
 	(((mo)->mo_flags & (f)) == (f))
 #define MEMBEROF_DANGLING_CHECK(mo) \
@@ -571,7 +573,7 @@ memberof_op_add( Operation *op, SlapReply *rs )
 				}
 
 				if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-					rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+					rc = rs->sr_err = mo->mo_dangling_err;
 					rs->sr_text = "adding non-existing object "
 						"as group member";
 					send_ldap_result( op, rs );
@@ -649,7 +651,7 @@ memberof_op_add( Operation *op, SlapReply *rs )
 				}
 
 				if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-					rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+					rc = rs->sr_err = mo->mo_dangling_err;
 					rs->sr_text = "adding non-existing object "
 						"as memberof";
 					send_ldap_result( op, rs );
@@ -836,7 +838,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
 						}
 		
 						if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-							rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+							rc = rs->sr_err = mo->mo_dangling_err;
 							rs->sr_text = "adding non-existing object "
 								"as group member";
 							send_ldap_result( op, rs );
@@ -933,7 +935,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
 						}
 
 						if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-							rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+							rc = rs->sr_err = mo->mo_dangling_err;
 							rs->sr_text = "deleting non-existing object "
 								"as memberof";
 							send_ldap_result( op, rs );
@@ -1044,7 +1046,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
 				op->o_bd->bd_info = (BackendInfo *)on;
 				if ( rc != LDAP_SUCCESS ) {
 					if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
-						rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+						rc = rs->sr_err = mo->mo_dangling_err;
 						rs->sr_text = "adding non-existing object "
 							"as memberof";
 						send_ldap_result( op, rs );
@@ -1490,6 +1492,10 @@ memberof_db_init(
 	memberof_t	tmp_mo = { 0 }, *mo;
 
 	mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) );
+
+	/* safe default */
+	mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION;
+
 	on->on_bi.bi_private = (void *)mo;
 
 	return 0;
@@ -1499,12 +1505,16 @@ enum {
 	MO_DN = 1,
 	MO_DANGLING,
 	MO_REFINT,
+	MO_GROUP_OC,
+	MO_MEMBER_AD,
+	MO_MEMBER_OF_AD,
 #if 0
 	MO_REVERSE,
 #endif
-	MO_GROUP_OC,
-	MO_MEMBER_AD,
-	MO_MEMBER_OF_AD
+
+	MO_DANGLING_ERROR,
+
+	MO_LAST
 };
 
 static ConfigDriver mo_cf_gen;
@@ -1570,6 +1580,13 @@ static ConfigTable mo_cfg[] = {
 		NULL, NULL },
 #endif
 
+	{ "memberof-dangling-error", "error code",
+		2, 2, 0, ARG_MAGIC|MO_DANGLING_ERROR, mo_cf_gen,
+		"( OLcfgOvAt:18.7 NAME 'olcMemberOfDanglingError' "
+			"DESC 'Error code returned in case of dangling back reference' "
+			"SYNTAX OMsDirectoryString SINGLE-VALUE )",
+		NULL, NULL },
+
 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
 };
 
@@ -1581,6 +1598,7 @@ static ConfigOCs mo_ocs[] = {
 		"MAY ( "
 			"olcMemberOfDN "
 			"$ olcMemberOfDangling "
+			"$ olcMemberOfDanglingError"
 			"$ olcMemberOfRefInt "
 			"$ olcMemberOfGroupOC "
 			"$ olcMemberOfMemberAD "
@@ -1683,6 +1701,25 @@ mo_cf_gen( ConfigArgs *c )
 			}
 			break;
 
+		case MO_DANGLING_ERROR:
+			if ( mo->mo_flags & MEMBEROF_FDANGLING_ERROR ) {
+				char buf[ SLAP_TEXT_BUFLEN ];
+				enum_to_verb( slap_ldap_response_code, mo->mo_dangling_err, &bv );
+				if ( BER_BVISNULL( &bv ) ) {
+					bv.bv_len = snprintf( buf, sizeof( buf ), "0x%x", mo->mo_dangling_err );
+					if ( bv.bv_len < sizeof( buf ) ) {
+						bv.bv_val = buf;
+					} else {
+						rc = 1;
+						break;
+					}
+				}
+				value_add_one( &c->rvalue_vals, &bv );
+			} else {
+				rc = 1;
+			}
+			break;
+
 		case MO_REFINT:
 			c->value_int = MEMBEROF_REFINT( mo );
 			break;
@@ -1742,6 +1779,15 @@ mo_cf_gen( ConfigArgs *c )
 			mo->mo_flags |= dangling_mode[ i ].mask;
 			break;
 
+		case MO_DANGLING_ERROR:
+			i = verb_to_mask( c->argv[ 1 ], slap_ldap_response_code );
+			if ( !BER_BVISNULL( &slap_ldap_response_code[ i ].word ) ) {
+				mo->mo_dangling_err = slap_ldap_response_code[ i ].mask;
+			} else if ( lutil_atoix( &mo->mo_dangling_err, c->argv[ 1 ], 0 ) ) {
+				return 1;
+			}
+			break;
+
 		case MO_REFINT:
 			if ( c->value_int ) {
 				mo->mo_flags |= MEMBEROF_FREFINT;
@@ -1880,7 +1926,7 @@ memberof_db_open(
 		}
 	}
 
-    if( ! mo->mo_oc_group ){
+	if( ! mo->mo_oc_group ){
 		mo->mo_oc_group = oc_find( SLAPD_GROUP_CLASS );
 		if ( mo->mo_oc_group == NULL ) {
 			Debug( LDAP_DEBUG_ANY,