Client Access License Calculator
CALs follow the people and devices, not the servers. Count who connects, subtract the users whose Microsoft 365 plan already includes the right, and add the Remote Desktop, SQL Server and Rights Management CALs no cloud plan covers.
How CALs work
One CAL covers every server
A Windows Server CAL lets one user (or one device) access any number of Windows Server machines of the same or earlier version. You count people or devices, never servers.
User or Device CALs
User CALs suit people who work from several devices. Device CALs suit shared devices such as shift workstations or kiosks used by many people.
What Microsoft 365 already covers
Microsoft 365 E3, E5 and F3 and Enterprise Mobility + Security include Windows Server CAL rights for licensed users. They do not cover Remote Desktop Services, SQL Server or on-premises Rights Management CALs.
External Connector
Customers and partners who are not your employees can be licensed per server with an External Connector instead of individual CALs. It pays off once enough outside users reach the same server.
window.C2N = (function () { function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); } function fire(el) { el.dispatchEvent(new Event('input', { bubbles: true })); el.dispatchEvent(new Event('change', { bubbles: true })); } function enhance(form) { [].forEach.call(form.querySelectorAll('select[data-seg]'), function (sel) { var seg = document.createElement('div'); seg.className = 'c2n-seg'; seg.setAttribute('role', 'radiogroup'); seg.style.gridTemplateColumns = 'repeat(' + Math.min(sel.options.length, +sel.dataset.seg || sel.options.length) + ',1fr)'; [].forEach.call(sel.options, function (o) { var b = document.createElement('button'); b.type = 'button'; b.textContent = o.textContent; b.dataset.v = o.value; b.setAttribute('role', 'radio'); b.addEventListener('click', function () { sel.value = o.value; sync(form); fire(sel); }); seg.appendChild(b); }); sel.hidden = true; sel.parentNode.insertBefore(seg, sel.nextSibling); }); [].forEach.call(form.querySelectorAll('input[data-range]'), function (num) { var r = num.dataset.range.split(','), rg = document.createElement('input'); rg.type = 'range'; rg.min = r[0]; rg.max = r[1]; rg.step = r[2] || 1; rg.className = 'c2n-range'; rg.setAttribute('aria-label', num.name); rg.addEventListener('input', function (e) { e.stopPropagation(); num.value = rg.value; fire(num); }); num.parentNode.appendChild(rg); }); } function sync(form) { [].forEach.call(form.querySelectorAll('select[data-seg]'), function (sel) { [].forEach.call(sel.nextSibling.children, function (b) { var on = b.dataset.v === sel.value; b.classList.toggle('on', on); b.setAttribute('aria-checked', on); }); }); [].forEach.call(form.querySelectorAll('input[data-range]'), function (num) { num.parentNode.querySelector('.c2n-range').value = num.value; }); } function render(el, r) { var h = '<div class="c2n-cx-bar"><span>Results · ' + esc(r.title) + (r.unit === undefined ? ' · USD' : r.unit) + '</span><span class="c2n-cx-live">Live</span></div>'; if (r.lead) h += '<p class="c2n-cx-lead">' + r.lead + '</p>'; if (r.kpis) h += '<div class="c2n-cx-kpis">' + r.kpis.map(function (k, i) { return '<div class="c2n-cx-kpi' + (i ? '' : ' on') + '"><small>' + esc(k[0]) + '</small><b>' + k[1] + '</b><span>' + (k[2] || '') + '</span></div>'; }).join('') + '</div>'; if (r.rows) { var cell = function (tag) { return function (c, i) { return '<' + tag + (i ? ' class="n"' : '') + '>' + c + '</' + tag + '>'; }; }; h += '<div class="c2n-cx-scroll"><table class="c2n-cx-table">' + (r.head ? '<tr>' + r.head.map(cell('th')).join('') + '</tr>' : '') + r.rows.map(function (row) { return '<tr>' + row.map(cell('td')).join('') + '</tr>'; }).join('') + (r.total ? '<tr class="t">' + r.total.map(cell('td')).join('') + '</tr>' : '') + '</table></div>'; } h += '<div class="c2n-cx-foot"><p>' + (r.note || '') + '</p>' + (r.cta ? '<a class="c2n-cx-btn" href="' + esc(r.cta[1]) + '">' + esc(r.cta[0]) + '</a>' : '') + '</div>'; el.innerHTML = h; } function money(n, d) { return (n < 0 ? '-$' : '$') + Math.abs(n).toLocaleString('en-US', { minimumFractionDigits: d || 0, maximumFractionDigits: d || 0 }); } function values(form) { var v = {}; [].forEach.call(form.elements, function (el) { if (el.name) v[el.name] = el.type === 'number' ? Math.max(0, +el.value || 0) : el.value; }); return v; } function restore(form) { var q = new URLSearchParams(location.search); [].forEach.call(form.elements, function (el) { if (el.name) { if (q.has(el.name)) el.value = q.get(el.name); } }); } function save(form) { var o = {}; [].forEach.call(form.elements, function (el) { if (el.name) o[el.name] = el.value; }); history.replaceState(null, '', '?' + new URLSearchParams(o)); } function mount(form, calc) { enhance(form); restore(form); var run = function () { sync(form); calc(values(form)); save(form); }; form.addEventListener('input', run); form.addEventListener('submit', function (e) { e.preventDefault(); }); run(); } return { mount: mount, render: render, money: money, esc: esc, sync: sync, enhance: enhance }; })(); (function () { var P = {"Windows Server 2025 - 1 User CAL":{"Education|One-time purchase (perpetual)":12.0,"Nonprofit|One-time purchase (perpetual)":20.0,"Commercial|One-time purchase (perpetual)":50.0},"Windows Server 2025 - 1 Device CAL":{"Commercial|One-time purchase (perpetual)":39.0,"Nonprofit|One-time purchase (perpetual)":15.0,"Education|One-time purchase (perpetual)":9.0},"Windows Server 2025 Remote Desktop Services - 1 User CAL":{"Nonprofit|One-time purchase (perpetual)":34.0,"Commercial|One-time purchase (perpetual)":174.0,"Education|One-time purchase (perpetual)":34.0},"Windows Server 2025 Remote Desktop Services - 1 Device CAL":{"Nonprofit|One-time purchase (perpetual)":34.0,"Commercial|One-time purchase (perpetual)":174.0,"Education|One-time purchase (perpetual)":34.0},"SQL Server 2025 - 1 User CAL":{"Education|One-time purchase (perpetual)":57.0,"Nonprofit|One-time purchase (perpetual)":91.0,"Commercial|One-time purchase (perpetual)":229.0},"SQL Server 2025 - 1 Device CAL":{"Education|One-time purchase (perpetual)":57.0,"Nonprofit|One-time purchase (perpetual)":91.0,"Commercial|One-time purchase (perpetual)":229.0},"Rights Management Services (RMS) 2025 CAL- 1 User":{"Nonprofit|One-time purchase (perpetual)":25.0,"Commercial|One-time purchase (perpetual)":63.0,"Education|One-time purchase (perpetual)":15.0},"Rights Management Services (RMS) 2025 CAL-1 Device":{"Nonprofit|One-time purchase (perpetual)":19.0,"Commercial|One-time purchase (perpetual)":49.0,"Education|One-time purchase (perpetual)":12.0},"Windows Server 2025 External Connector":{"Nonprofit|One-time purchase (perpetual)":610.0,"Commercial|One-time purchase (perpetual)":2443.0,"Education|One-time purchase (perpetual)":610.0}}; var $ = C2N.money; function p(name, seg) { return (P[name] || {})[seg + '|One-time purchase (perpetual)'] || 0; } C2N.mount(document.getElementById('ca'), function (v) { var u = v.type === 'u', who = u ? 'User' : 'Device', seg = v.seg; var ws = Math.max(0, v.n - v.cov), wsP = p('Windows Server 2025 - 1 ' + who + ' CAL', seg); var rdsP = p('Windows Server 2025 Remote Desktop Services - 1 ' + who + ' CAL', seg), sqlP = p('SQL Server 2025 - 1 ' + who + ' CAL', seg); var rmsP = p(u ? 'Rights Management Services (RMS) 2025 CAL- 1 User' : 'Rights Management Services (RMS) 2025 CAL-1 Device', seg); var ecP = p('Windows Server 2025 External Connector', seg), extCal = v.ext * wsP, extEc = Math.max(1, v.extsrv) * ecP, useEc = v.ext > 0 ? extEc < extCal : false; var rows = [[ws + ' Windows Server ' + who + ' CALs', ws, $(wsP), $(ws * wsP)], [v.rds + ' Remote Desktop ' + who + ' CALs', v.rds, $(rdsP), $(v.rds * rdsP)], [v.sql + ' SQL Server ' + who + ' CALs', v.sql, $(sqlP), $(v.sql * sqlP)], [v.rms + ' RMS ' + who + ' CALs', v.rms, $(rmsP), $(v.rms * rmsP)]].filter(function (r) { return r[1]; }).map(function (r) { return [r[0], r[2], r[3]]; }); var ext = v.ext ? (useEc ? extEc : extCal) : 0; if (v.ext) rows.push([useEc ? Math.max(1, v.extsrv) + ' External Connector' + (v.extsrv > 1 ? 's' : '') : v.ext + ' CALs for external users', useEc ? $(ecP) : $(wsP), $(ext)]); var total = ws * wsP + v.rds * rdsP + v.sql * sqlP + v.rms * rmsP + ext, saved = Math.min(v.cov, v.n) * wsP; C2N.render(document.getElementById('ca-out'), { title: 'Client access licenses', lead: '<strong>' + (ws + v.rds + v.sql + v.rms) + ' CALs to buy.</strong> Microsoft 365 already covers ' + Math.min(v.cov, v.n) + ' of your ' + v.n + ' ' + who.toLowerCase() + 's for Windows Server, worth ' + $(saved) + '.' + (v.ext ? ' For ' + v.ext + ' external users, ' + (useEc ? 'the External Connector is cheaper.' : 'individual CALs are cheaper than an External Connector.') : ''), kpis: [['One-time total', $(total), 'perpetual licenses'], ['Already covered', $(saved), 'by Microsoft 365 rights']], head: ['License', 'Each', 'Total'], rows: rows.length ? rows : [['Nothing to buy', '', '$0']], total: ['Total, one-time', '', $(total)], note: 'Microsoft US list price, ' + seg + ', current month, perpetual. A person confirms every quote.', cta: ['Request a quote', '/tools/forms/?f=quote&items=' + encodeURIComponent(ws + ' Windows Server ' + who + ' CALs; ' + v.rds + ' RDS CALs; ' + v.sql + ' SQL CALs; ' + v.rms + ' RMS CALs' + (v.ext ? '; external: ' + (useEc ? v.extsrv + ' External Connector' : v.ext + ' CALs') : '') + '; est. ' + $(total))] }); }); })();