The current take is that CU9 and CU27 just handed Linux SQL Server admins a clean least-privilege win. I ran it for a week against a real pipeline account and I’ll say it plainly: this is a lateral move dressed up as a promotion. Narrower than sysadmin? Yes. “Least privilege”? Only if you don’t look at what BULK INSERT actually touches.
Let me steelman the cheerful version first, because it’s not wrong. For years, running ETL on SQL Server for Linux meant a bad choice: grant the service account sysadmin or hand it db_owner on every target database, because the ADMINISTER BULK OPERATIONS permission — and the bulkadmin fixed server role that wraps it — simply didn’t exist on Linux. Windows has had it since SQL Server 2000. On Linux you either over-granted or you rewrote your loaders to avoid BULK INSERT and OPENROWSET(BULK) entirely. Neither is fun to explain to an auditor. So yes: SQL Server 2025 CU9 and SQL Server 2022 CU27 closing that gap is real, and bulkadmin genuinely blocks the things sysadmin doesn’t — schema changes, principal management, backup/restore, linked-server config. If your only other option was god mode, this is strictly better. Take the win.
Now the part the update note doesn’t dwell on.
What bulkadmin actually hands the holder
bulkadmin is a server-level role. The permission it grants, ADMINISTER BULK OPERATIONS, lets a principal read files from the filesystem as the mssql service account and stream them into any table it has INSERT on. That’s the whole point of BULK INSERT and OPENROWSET(BULK), and it’s also the problem. The role doesn’t scope you to “the ETL landing directory.” It scopes you to “anything the mssql Linux user can read.”
Consider that: on a default install that’s /var/opt/mssql — trace files, error logs, other databases’ backup files if someone dropped them there, any NFS or SMB share you’ve mounted for staging. Give an account bulkadmin plus INSERT on one throwaway table it owns, and you’ve built a file-exfiltration primitive: OPENROWSET(BULK ... SINGLE_CLOB) into that table, then SELECT it back out. Not sysadmin. Not nothing, either. At 2 a.m. when a pipeline identity’s token leaks, “they could read arbitrary files off the box” is not the incident summary you want.
So grant it — but grant it knowing it’s a server-wide role, keep the mssql account’s filesystem footprint tight, and don’t pretend the blast radius ends at your staging folder.
The audit trail is thinner than you’d like
The grant audits cleanly. Add the SERVER_ROLE_MEMBER_CHANGE_GROUP action group to a server audit spec and every ALTER SERVER ROLE ... ADD MEMBER lands in the log. Do that before you hand the role out, not after.
Here’s the catch, and I’ll flag this as what I saw rather than gospel: across a week on a 2022 CU27 box, the bulk operations never threw a dedicated audit action. A BULK INSERT landed in my audit as an ordinary INSERT; the OPENROWSET(BULK) read came through looking like a SELECT. There’s no “someone used their bulk privilege to read a file” event that I could find. Verify it against your own build and action groups before you bet a control on it — but if your compliance story depends on proving which files an ETL identity touched, don’t assume the audit log carries that for you. You may be reconstructing it from source paths in query text, if you captured those at all.
On Managed Instance, this is mostly a non-event
The brief asked whether this extends to Azure SQL Managed Instance. Straight answer: no, because there’s nothing to extend — these CUs ship to the standalone SQL Server product on its own servicing channel, and MI is a separate PaaS service that already exposes the bulkadmin fixed server role through the shared engine. The Linux parity gap was a box-product problem; MI was never on the wrong side of it.
And the question is slightly backwards anyway. MI’s bulk-load path for modern pipelines isn’t filesystem BULK INSERT — it’s loading from Azure Blob Storage through a DATABASE SCOPED CREDENTIAL and an external data source, gated by the database-scoped ADMINISTER DATABASE BULK OPERATIONS permission. That permission is the actual least-privilege answer this whole conversation should be about: scoped to one database, tied to a credential you control, pointed at blob instead of a shared filesystem. One thing not to assume on MI: role-membership changes you make with T-SQL are captured by SQL Audit the same way they are on the box — don’t expect them in the Azure Activity Log, which tracks control-plane operations against the instance resource, not the statements you run inside it.
So the honest framing: if you run SQL Server on a Linux VM and your loaders depend on BULK INSERT from local or mounted storage, CU9/CU27 finally lets you stop over-granting, and you should take it today. Just scope the service account’s filesystem access as if the role is a file-read capability — because it is. If you’re on MI or building something new, reach for ADMINISTER DATABASE BULK OPERATIONS and blob-scoped credentials and skip the server role entirely. The parity gap is closed. The “least privilege” part is still your job.
