Set how long Moodle learners keep access — by course, cohort, or individual learner
Access windows live in a few different places in Moodle, and there's no single screen that ties them together — so a 365-day rule, a cohort intake, and "extend this one learner who just renewed" each become their own errand. Here's how each works today, and the free plugin we built to run all of it from one place.
timeend): when it passes, Moodle applies the method's expiry action — keep, suspend, or unenrol. You can set that per user, or a default duration per method, but the settings are scattered and cohort sync has no end-date field of its own. Access Expiry & Enrolment Duration (local_accessexpiry) is our free, GPLv3 plugin that manages it from one place: set a window by site, category, course, role, enrolment method or cohort; extend individual learners; and send optional reminders — with a dry-run preview, an audit log, and a revert tool so it's safe on a live site.Download the plugin (ZIP) View on GitHub How to install
Three questions land in an LMS admin's inbox in the same week: "Can we make this course expire a year after each person starts?" "The spring intake finished — take their access down, but keep the records." "Dana just re-paid, put her back in."
All three are the same underlying thing — how long a learner keeps access — but in Moodle they're answered in different places. A per-course default here, a per-user end date there, a cohort that has no end-date field at all, and a re-enrol that quietly leaves someone suspended. Each is doable; together they add up to a lot of clicking, and it's easy to get one wrong.
We kept meeting this on training platforms — annual re-certification, term intakes, paid access that renews — so we built one plugin that holds all of it in a single, careful place, and released it free. This post is the honest version: how access duration actually works in Moodle, the manual ways to set it, and where the plugin picks up.
The mechanism
How access duration works in Moodle
Every enrolment record (mdl_user_enrolments) has a start (timestart) and an end (timeend). A learner has access while the current time is between them; timeend = 0 means no end. When timeend passes, the enrolment expires and Moodle applies that method's expiry action — keep the learner enrolled, suspend them, or unenrol them.
Those three actions matter, because they do different things to a learner's record:
- Suspend keeps the enrolment and every grade, and simply blocks access. It's the reversible, safe choice.
- Unenrol removes the enrolment; the live grade rows move to grade history, where they can be recovered on re-enrol. (We wrote up that recovery in Moodle grades gone after re-enrolment? They're not.)
- Keep leaves access untouched — useful only for reporting.
So "how long does this person keep access?" comes down to setting timeend and choosing the expiry action. The manual and self enrolment methods expose both; a couple of common cases just take a little assembly.
The manual way
Setting durations by hand
One learner, one course. On the course's Participants page, edit their enrolment and set an Enrolment ends date. Access shuts off at that moment; nothing else is needed. Good for a handful of people. (More on this in Give Moodle learners access until a date — without cohort sync.)
A default for a whole course. On a manual or self enrolment method you can set a Default enrolment duration, so new enrolments get an end date automatically. It applies going forward, per course and per method.
A cohort intake. Cohort sync keeps everyone in the cohort enrolled, which is exactly what you want for bulk enrolment — and to give that group a time limit you carry the window on the enrolment and remove members once it passes. We first solved this with a guarded cron script, written up in Moodle cohort memberships never expire — here's how we make them lapse after a year.
Each of these is the right tool for its case. What there isn't, in core, is one screen that sets the policy once and applies it everywhere — or a single, fast way to extend an individual after they renew. Rebuild that by hand every term and you've written a plugin. So we did.
The tool
Access Expiry & Enrolment Duration — one place for all of it
Access Expiry & Enrolment Duration (local_accessexpiry) is a Moodle local plugin. It adds a section under Site administration → Users → Access Expiry & Enrolment Duration where you set the access window once and choose exactly where it applies. Rules cascade from broad to specific — a site default, then category, course, role, enrolment method, or cohort — and the most specific rule wins. Per-learner extensions sit on top and always win. A typical rule: expire access 365 days after each learner enrols, then suspend so their grades are kept — set once, applied everywhere it should apply.
For direct enrolments (manual, self) it writes the resolved end date onto each enrolment and applies your chosen action when the window passes — suspend by default, so grades are kept. For cohorts it carries the policy on the cohort and removes lapsed members safely, so bulk enrolment and time-limited access finally work together.
What it does
The feature set, plainly
- Rules across scopes — a window in days or to a fixed date, set at site, category, course, role, enrolment method or cohort level; most specific wins.
- Cohort access windows — give a synced cohort an end date, and members lapse on schedule instead of staying enrolled forever.
- Choose the expiry action — suspend (keeps grades — the default), unenrol, suspend and remove roles, or report only.
- Per-learner extensions — extend one learner by days, to a date, or to unlimited, with a reason recorded. If they were suspended, extending re-activates them with grades intact.
- Optional reminders — staged "your access is ending soon" messages on your own schedule, with an editable message and a renew link, sent through Moodle's notification system.
- Delegation — a single capability lets support staff extend a learner without full enrolment control.
The daily job
Extending one learner after they renew
The most common request isn't a policy change — it's "put this person back." In a course, Access & extensions lists the enrolled learners with their current access-end date. Find one (there's a type-ahead search), choose to add days, set a new date, or make it unlimited, write a short reason, and save. It's recorded against your name in the audit log.
The important part is what happens to someone whose access already lapsed: because the default expiry action is suspend, their enrolment and grades are still there. Extending them flips the suspension back to active — they're in again immediately, with everything they'd done intact. No re-enrol, no "I paid but I'm still locked out."
Careful by default
Safe to put on a live site
A plugin that can change access for a lot of people at once has to earn trust, so we built it to be cautious by default:
- Ships switched off. On install it does nothing — disabled, with the site default set to "never expire."
- Dry-run first. Turn it on and it runs in Observe mode: it calculates and shows exactly what a live run would change, and changes nothing.
- A deliberate go-live. The Go-Live page shows the real numbers — how many end dates it will set, suspend, or remove — and asks you to type that number to confirm.
- Protected people. Site administrators and roles you nominate are never affected, and each run is capped so a backlog drains gradually.
- Every change logged, and reversible. An audit log records the before-and-after of each change, and a revert tool can restore prior access.
Before releasing it, we reviewed it end to end — security, correctness, privacy, and Moodle's coding standards.
Get it
Installing Access Expiry & Enrolment Duration
It installs like any Moodle plugin, no server shell required:
- Download the plugin ZIP (or get the source from GitHub).
- In Moodle: Site administration → Plugins → Install plugins, upload the ZIP, and install.
- Run the upgrade when prompted, then open it under Site administration → Users → Access Expiry & Enrolment Duration. It starts disabled — set your policy, preview in dry-run, then go live when you're ready.
Requirements: Moodle 4.5 (LTS) or newer. It's free and GPLv3.
When you need access to behave a specific way
This plugin exists because time-limited access shows up in a dozen forms — annual re-certification, term intakes, paid windows that renew, contractors who roll off — and wiring each one by hand gets old. If your access rules don't quite fit what core Moodle offers, that's routine Moodle development work for us, and the broadly useful pieces become free releases like this one. We reply within one business day.
Quick answers
Questions people ask about this
How do I make a Moodle enrolment expire after a set time?
Each enrolment has an end date (timeend); when it passes, the enrolment expires and Moodle applies the method's expiry action (keep, suspend, or unenrol). You can set it per user on a manual or self enrolment, or a default duration on the method. To set it once and have it apply by course, category, role, method or cohort — including cohort-synced learners — Access Expiry & Enrolment Duration handles all of it from one screen.
Can a Moodle cohort sync enrolment have an end date?
Cohort sync keeps members enrolled while they're in the cohort. To add a time limit you carry the access window on the enrolment. Access Expiry lets you set a per-cohort policy — expire after a number of days, or on a fixed date — and removes lapsed members safely, so cohort enrolment and time-limited access work together.
How do I extend one learner's access in Moodle?
You can edit a single enrolment's end date on the participants list. Access Expiry adds a course-level "Access & extensions" screen where you extend a learner by days, to a fixed date, or to unlimited, with a reason recorded. If the learner was suspended when their window ended, extending re-activates the enrolment so grades and work are kept.
Does expiring access delete a learner's grades?
It depends on the action. Suspend keeps the enrolment and all grades and just blocks access — the safe default. Unenrol moves grades to grade history, where they can be recovered on re-enrol. Access Expiry defaults to suspend and, when you extend or renew a suspended learner, restores access with grades intact.
Is the Access Expiry plugin safe to run on a live Moodle site?
It's built for it. It ships disabled and in dry-run, which previews exactly how many enrolments a live run would change without touching anything. Going live shows the numbers and asks you to confirm them. Site admins and protected roles are never affected, each run is capped, every change is logged, and a revert tool can restore prior access.
Where do I download it?
The installable ZIP is on this page and the plugins page; the source is on GitHub. It's free and GPLv3, for Moodle 4.5 (LTS) and newer. The Moodle Marketplace listing is under review; once approved you'll install it from within Moodle by name.