First published on TechNet on Oct 29, 2015
Hello, Ryan Ries here with my first AskDS post! I recently ran into an issue with a particular environment where Active Directory and UNIX systems were being integrated. Microsoft has several attributes in AD to facilitate this, and one of those attributes is the memberUid attribute on security group objects. You add user IDs to the memberUid attribute of the security group, and Active Directory will treat that as group membership from UNIX systems for the purposes of authentication/authorization.
All was well and good for a long time. The group grew and grew to over a thousand users, until one day we wanted to add another UNIX user, and we were greeted with this error:
“The administrative limit for this request was exceeded.”
Wait, there’s a limit on this attribute? I wonder what that limit is.
MSDN documentation states that the rangeUpper property of the memberUid attribute is 256,000. This support KB also mentions that:
“The attribute size limit for the memberUID attribute in the schema is 256,000 characters. It depends on the individual value length on how many user identifiers (UIDs) will fit into the attribute.”
And you can even see it for yourself if you fancy a gander at your schema:
Something doesn’t add up here – we’ve only added around 1200 users to the memberUid attribute of this security group. Sure it’s a big group, but that doesn’t exceed 256,000 characters; not even close. Adding up all the names that I’ve added to the attribute, I figure it adds up to somewhere around 10,000 characters. Not 256,000.
So what gives?
(If you’ve been following along and you’ve already figured out the problem yourself, then please contact us! We’re hiring! )
The problem here is that we’re hitting a different limit as we continue to add members to the memberUid attribute, way before we get to 256k characters.
The memberUid attribute is a multivalued attribute, however it is not a linked attribute. This means that it has a limitation on its maximum size that is less than the 256,000 characters shown on the memberUid attributeSchema object.
You can distinguish between which attributes are linked or not based on whether those attributeSchema objects have values in their linkID attribute.
Example of a multivalued and linked attribute:
Example of a multivalued but not linked attribute:
So if the limit is not really 256,000 characters, then what is it?
From How the Data Store Works on TechNet:
“The maximum size of a database record is 8110 bytes, based on an 8-kilobyte (KB) page size. Because of variable overhead requirements and the variable number of attributes that an object might have, it is impossible to provide a precise limit for the maximum number of multivalues that an object can store in its attributes. …
The only value that can actually be computed is the maximum number of values in a nonlinked, multivalued attribute when the object has only one attribute (which is impossible). In Windows 2000 Active Directory, this number is computed at 1575 values. From this value, taking various overhead estimates into account and generalizing about the other values that the object might store, the practical limit for number of multivalues stored by an object is estimated at 800 nonlinked values per object across all attributes.
Attributes that represent links do not count in this value. For example, the members linked, multivalued attribute of a group object can store many thousands of values because the values are links only.
The practical limit of 800 nonlinked values per object is increased in Windows Server 2003 and later. When the forest has a functional level of Windows Server 2003 or higher, for a theoretical record that has only one attribute with the minimum of overhead, the maximum number of multivalues possible in one record is computed at 3937. Using similar estimates for overhead, a practical limit for nonlinked multivalues in one record is approximately 1200 . These numbers are provided only to point out that the maximum size of an object is somewhat larger in Windows Server 2003 and later.”
(Emphasis is mine.)
Alright, so according to the above article, if I’m in an Active Directory domain running all Server 2003 or better, which I am, then a “practical” limit for non-linked multi-value attributes should be approximately 1200 values.
So let’s put that to the test, shall we?
I wrote a quick and dirty test script with PowerShell that would generate a random 8-character string from a pool of characters (i.e., a random fictitious user ID,) and then add that random user ID to the memberUid attribute of a security group, in a loop until the script encounters an error because the script can’t add any more values:
# This script is for testing purposes only!
$ValidChars = @('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7','8', '9')[String]$Str = [String]::Empty
[Int]$Bytes = 0
[Int]$Uids = 0
While ($Uids -LT 1000000)
{
$Str = [String]::Empty
1..8 | % { $Str += ($ValidChars | Get-Random) }
Try
{
Set-ADGroup 'TestGroup' -Add @{ memberUid = $Str } -ErrorAction Stop
}
Catch
{
Write-Error $_.Exception.Message
Write-Host "$Bytes bytes $Uids users added"
Break
}
$Bytes += 8
$Uids += 1
}
Here’s the output from when I run the script:
Huh… whaddya’ know? Approximately 1200 users before we hit the “administrative limit,” just like the article suggests.
One way of getting around this attribute's maximum size would be to use nested groups, or to break the user IDs apart into two separate groups… although this may cause you to have to change some code on your UNIX systems. It’s typically not a fun day when you first realize this limit exists. Better to know about it beforehand.
Another attribute in Active Directory that could potentially hit a similar limit is the servicePrincipalName attribute, as you can read about in this AskPFEPlat article .
Update 11/14/2024: Hey it's Ryan again! I came back to this post again today because I noticed that the images got deleted in the most recent blog migration. I came back to fix the images. But while I'm here, I wanted to clarify some things that I've learned about this topic in the 10 years since I first wrote this article.
There are many blog posts and articles that talk about this specific scalability limit, and most of them mention the size of the 8KB database page. I used to tell people the values you add to a non-linked multivalue attribute must fit within an 8KB database page. But that isn't a very accurate statement. The attribute actually stores LIDs (long value IDs) which are pointers to the data. In Server 2022 and below, those LIDs are 4 bytes. You can theoretically fit 2096 4-byte values into 8KB, however, there is still overhead that occupies a lot of space, and is variable based on your environment. It is difficult-to-impossible to calculate precisely and varies for every different deployment and attribute, so the best we can do is approximate: "You can fit about 1200 values in there." On some DCs and for some attributes, it might be 900 or 1100 or 1500. The average is about 1200. You might figure this out on your own by testing and seeing that the limit for your particular environment is for example, 1264 values before reaching the limit, regardless of the length of the text of the individual values.
In Server 2025, we now have the ability to use 32KB database pages instead of 8KB database pages. This increases the number of values you can store in a nonlinked multivalue attribute, but not by as much as you might have thought. Even though 32KB is 4x as big as 8KB, you can only store ~3200 values now instead of ~1200. The primary reason being is that now in Server 2025, LIDs (the pointers) are 8 bytes instead of 4 bytes each.
Then you still have that "overhead," which I have taken to calling "dark matter," that prevents you from storing as many values in there as you think you should be able to.
Until next time!
Ryan Ries