
This post is about load testing Microsoft Remote Desktop Services on Windows Server — concurrent RDP sessions on Remote Desktop Session Hosts — not Amazon RDS, the Relational Database Service. Search engines treat “RDS load testing” as a database topic. If you are here to soak a SQL instance, stop. If you need a concurrent-user number for Windows Server RDS that a CAB will accept, keep reading.
This is a 2026 method for VDI and RDS admins and QA. The stack is Windows Server Remote Desktop Services, Remote Desktop Session Host (RDSH) collections, RD Gateway, RD Web Access, and the real Remote Desktop client. Azure Virtual Desktop (AVD) is a cousin: same RDP family, different control plane. An AVD density figure is not an on-prem RDS figure.
RDP is not HTTP
Most load-testing practice grew up on websites. You record HTTP, replay thousands of threads, and graph page time. That model does not describe a Remote Desktop session.
Hammer RD Web Access with a web generator and you have load-tested the portal, not the session hosts.
RD Web Access is a web application. RD Gateway is an HTTPS front door that wraps RDP. The session that follows is Remote Desktop Protocol. The published desktop or RemoteApp does not send DOM or window handles to the endpoint. It sends pixels. The client sends keyboard and mouse.
A synthetic RDP stream that never paints a real Remote Desktop client window misses the events users wait on: the logon animation, the shell, the first paint of Epic or a line-of-business RemoteApp, the modal after a click. Those events exist on the bitmap. Treat RDP as a remoting protocol with a human on the other end, not as another API to replay.
What a defensible concurrent-user number actually is
A defensible number is not the highest session count you can boot before the Connection Broker returns errors. It is the highest concurrency at which a defined set of user transactions still meets a defined experience budget, with a defined failure rate, on the image and hardware you intend to ship. Write the acceptance line before the first ramp:
- Logon to a usable desktop: 45 seconds at p95, 60 seconds at p99.
- Launch the RemoteApp or in-session line-of-business app, search, open the record: 8 seconds at p95.
- Fewer than 1% of sessions fail, disconnect, or hang during the sustain.
- Session-host CPU, memory, and profile IOPS stay inside the same alert bands you already use in production.

When the run crosses that line, that concurrency is the number. Averages, “it still launched,” and a green RDSH CPU chart are not. RDP round-trip time is useful. It is not the same as “the chart appeared.”
Test the path users actually take
Users do not appear already inside an RDP session. They hit RD Web Access (internal) or RD Gateway (external and most hybrid designs), then authentication — Active Directory, MFA, smart card, or a mix — then collection enumeration, resource launch, RDP to the Remote Desktop Session Host, profile and GPO processing (FSLogix or a roaming profile), and only then the business application.

Skip RD Gateway in the lab because “it is just a proxy” and you will be surprised on go-live morning. Skip MFA because the tool cannot type an OTP and you have tested a path nobody uses. If production is Gateway plus MFA plus a published desktop collection, that is the script.
Pin Windows Server version, RDSH image, RDP client version, Connection Broker and Gateway builds, GPO, profile solution, and the published resource. A load test of a moving image is a story, not a measurement. AVD and Citrix have their own brokers and gateways; an RDS result does not transfer. Reuse the transactions and budgets; rebuild the connection script if you are comparing platforms.
Measure from the user’s screen
On RDP there are no client-side objects to bind to. The practical way to know a step finished is to watch the screen: image recognition and OCR against a baseline of what “done” looks like. Time the interval from the click or key until that image or text is visible.
GUI-level tools exist for this. CitraTest VU, for example, drives the real Remote Desktop client with keyboard and mouse, compares the live screen to baseline images, and does not install agents on the session hosts, the Connection Broker, or RD Gateway. Protocol replay and in-guest workload agents scale on cheaper generators, but they are not a substitute for “did the chart actually appear.”
Correlate the two views. When p95 “open chart” jumps from 6 seconds to 14 seconds at 180 users, you want RDSH CPU, logon duration, and profile IOPS on the same timeline. The screen tells you it broke. The infrastructure tells you which layer. If generator CPU is pegged, you are measuring the lab, not the session hosts.
FSLogix and profiles deserve their own watch. A session host that looks fine at 80 users can fall over at 81 if the profile store cannot keep up with concurrent logons. Measure container attach time, profile IOPS, and the delay from credentials accepted to a usable shell. That interval is often the real login-storm bottleneck, not RDSH CPU.
A seven-step method you can take to a CAB

- Freeze the image and the client. Record the collection, machine profile, Windows Server build, RDP client, RD Web Access, RD Gateway, Connection Broker, and image hash. If you change any of those mid-test, start over. Capacity is always “on this build.”
- Script the business day, not only a login. Logon is mandatory. It is not the workload. Script the five to ten transactions that represent a real hour: launch, search, open, save, print, switch RemoteApps, idle. Put think time in. Do not test a knowledge-worker desktop if most sessions are task workers on one RemoteApp.
- Take a single-user baseline, then a handful. One session, then five, on the same script. If one user already takes 40 seconds to a usable desktop, you do not have a capacity problem. You have an image, profile, or GPO problem. Fix that before you add concurrency.
- Ramp, then sustain — and run a login storm as its own test. A login storm — two hundred users authenticating in two minutes — is a real event: shift start, a DR test, Monday at 8:00. It is not the same as two hundred users already in session doing work. Run both shapes. Storm: steep ramp; measure logon time, Connection Broker and RD Gateway CPU, and the profile store. Steady state: slower ramp to target, then a sustain long enough for memory growth, CPU ready time, profile I/O, and session reliability to show up. Thirty minutes is a demo. Two hours is closer to a shift. If you only storm, you will size the logon path and under-size the session hosts. If you only sustain, you will miss 8 a.m.
- Watch the tail and the failures. Means hide the damage. Report p95 and p99 for every transaction, plus fail, retry, and disconnect counts. One stuck GPO or one saturated CIFS share will not move the average until the service desk is already taking calls.
- Stop at the acceptance line. Add concurrency in steps — 25 or 50 users is typical — until a transaction budget or a reliability budget is breached. The last step that still passed is the number you take to the business. Write down hardware, image, client version, script name, and the exact pass/fail table.
- Re-test when density-changing things change. New Windows Server feature update, new RDP client, FSLogix policy, an extra RemoteApp, different RDSH hardware, an RD Gateway or MFA change, a move from on-prem RDS to Azure Virtual Desktop. Capacity is not a one-time project.

FAQ
Can we web-test RD Web Access and call it an RDS load test?
You can load-test the portal that way. You cannot size session hosts, RDP, profiles, or the published application that way. RD Web Access and RD Gateway belong in the path. They are not the path.
How is Azure Virtual Desktop different from Windows Server RDS for this?
AVD is a cousin, not the same stack. Users still get an RDP session, but the broker, gateway, and host pool live in Azure. Do not assume an on-prem RDSH density number still holds after you move the workload. Rebuild the connection script; reuse the transactions and the budgets.
What about Citrix in the same environment?
Reuse the transactions and the budgets. Rebuild the connection for each protocol. An RDS concurrency figure is not a Citrix or AVD figure.
When is protocol-level RDP replay enough?
For a quick Connection Broker or RD Gateway soak, sometimes. For a number you will print on a capacity plan and live with at 8 a.m., measure the screen.
Take the number you can stand behind
A Microsoft RDS load test that a CAB will accept has four traits: it walks the real RD Web Access or RD Gateway path, it drives RDP from a real client, it ramps and then sustains (with a separate login-storm run), and it stops at a pre-written experience budget measured on the user’s screen.
When you need that GUI-level path — real Remote Desktop client, image and OCR, no agents on the session hosts — Tevron’s CitraTest VU is built for the job. See CitraTest VU load testing and Tevron’s notes on RDP load testing.