Skip to main content

Event Scheduler Basics

Learning Focus

Use this lesson to understand the MySQL Event Scheduler — a built-in job scheduler that lets you run SQL statements automatically on a schedule, without external tools like cron.

Concept Overview

What Is the Event Scheduler?

The MySQL Event Scheduler is a built-in scheduler that runs SQL statements at specified times or intervals. Think of it as cron inside your database — you define events with SQL, and MySQL executes them according to the schedule.

-- This event runs every day at midnight
CREATE EVENT cleanup_sessions
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_DATE + INTERVAL 1 DAY
DO
DELETE FROM sessions WHERE expires_at < NOW();

Why Use the Event Scheduler?

BenefitExplanation
No external dependenciesNo need for cron, systemd timers, or task schedulers
SQL-nativeWrite events in SQL; they have full access to your database
TransactionalEvents participate in MySQL's transaction system
Self-containedBackup the database and you backup the scheduled jobs too
PortableEvents move with your database to another server

Event Scheduler vs. Cron

FeatureEvent SchedulerCron / Systemd Timers
LanguageSQLShell commands
SetupSQL DDLOS configuration
Database accessDirectRequires mysql client connection
Backed up with DB❌ (separate backup needed)
OS-level tasks✅ (file operations, network calls)
MonitoringSHOW EVENTSsystemctl status, logs

Use the Event Scheduler for: database-internal tasks (cleanup, aggregation, archival) Use cron for: tasks that involve the OS, network, or external services


Basic Syntax & Rules

Enabling the Event Scheduler

The Event Scheduler is disabled by default in many MySQL installations:

-- Check current status
SHOW VARIABLES LIKE 'event_scheduler';

-- Enable for current session
SET GLOBAL event_scheduler = ON;

For permanent activation, add to my.cnf:

[mysqld]
event_scheduler = ON

Important: After a MySQL restart, the scheduler reverts to OFF unless configured in my.cnf.

One-Time Events

CREATE EVENT one_time_cleanup
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO
DELETE FROM temp_data WHERE created_at < NOW() - INTERVAL 24 HOUR;

This event runs once (1 hour from now) and then auto-drops itself.

Recurring Events

CREATE EVENT daily_cleanup
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_DATE + INTERVAL 1 DAY -- starts tomorrow midnight
DO
DELETE FROM sessions WHERE expires_at < NOW();

Event with Multi-Statement Body

Use BEGIN ... END for multiple statements:

DELIMITER //

CREATE EVENT daily_maintenance
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_DATE + INTERVAL 1 DAY
DO
BEGIN
-- Step 1: Clean expired sessions
DELETE FROM sessions WHERE expires_at < NOW();

-- Step 2: Log the cleanup
INSERT INTO maintenance_log (task, executed_at)
VALUES ('session_cleanup', NOW());
END //

DELIMITER ;

Key Schedule Options

OptionExampleMeaning
EVERY 1 HOURHourlyRepeat every N units
EVERY 5 MINUTEEvery 5 minutesShort intervals
EVERY 1 DAYDailyCommon for maintenance
EVERY 1 WEEKWeeklyWeekly reports
STARTS datetimeSTARTS '2026-02-11 00:00:00'When to start the schedule
ENDS datetimeENDS '2026-12-31 23:59:59'When to stop scheduling
ON COMPLETION PRESERVEKeep after expiryEvent stays visible after ENDS
ON COMPLETION NOT PRESERVEAuto-deleteDefault — event disappears

Step-by-Step Examples

Example 1: Enable the Scheduler and Create a Cleanup Event

Step 1: Enable the event scheduler

SET GLOBAL event_scheduler = ON;
SHOW VARIABLES LIKE 'event_scheduler';
Variable_nameValue
event_schedulerON

Step 2: Create the event

DELIMITER //

CREATE EVENT evt_cleanup_expired_sessions
ON SCHEDULE EVERY 1 HOUR
STARTS CURRENT_TIMESTAMP
COMMENT 'Remove expired sessions every hour'
DO
BEGIN
DELETE FROM sessions
WHERE expires_at < NOW()
LIMIT 10000;
END //

DELIMITER ;

Step 3: Verify the event was created

SHOW EVENTS FROM app_db\G

Expected output:

                  Db: app_db
Name: evt_cleanup_expired_sessions
Definer: root@localhost
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 1
Interval field: HOUR
Status: ENABLED

Example 2: One-Time Scheduled Task

Scenario: You need to archive data at a specific time (e.g., after business hours tonight).

CREATE EVENT evt_archive_old_orders
ON SCHEDULE AT '2026-02-10 23:00:00'
ON COMPLETION PRESERVE
COMMENT 'Archive orders older than 1 year'
DO
INSERT INTO orders_archive
SELECT * FROM orders
WHERE order_date < NOW() - INTERVAL 1 YEAR;

ON COMPLETION PRESERVE keeps the event visible after execution so you can verify it ran.


Example 3: Managing Events

-- List all events
SHOW EVENTS;

-- View event definition
SHOW CREATE EVENT evt_cleanup_expired_sessions\G

-- Temporarily disable an event
ALTER EVENT evt_cleanup_expired_sessions DISABLE;

-- Re-enable it
ALTER EVENT evt_cleanup_expired_sessions ENABLE;

-- Change the schedule
ALTER EVENT evt_cleanup_expired_sessions
ON SCHEDULE EVERY 30 MINUTE;

-- Rename an event
ALTER EVENT old_name RENAME TO new_name;

-- Drop an event
DROP EVENT IF EXISTS evt_cleanup_expired_sessions;

Practical Use Cases

1. Session Cleanup

Delete expired sessions hourly to keep the sessions table small and fast.

2. Temporary Data Purging

Remove old records from staging, import, or temporary tables on a schedule.

3. Audit Log Retention

Purge audit records older than the retention period (e.g., 90 days) every night.

4. Report Pre-Generation

Aggregate daily/weekly metrics into summary tables during off-peak hours.

5. Health Monitoring

Insert a heartbeat row every minute; external monitoring checks for freshness.


Common Mistakes & Troubleshooting

MistakeWhat HappensHow to Fix
Event scheduler is OFFEvents exist but never runSET GLOBAL event_scheduler = ON and add to my.cnf
Scheduler resets after restartEvents stop until manually re-enabledAdd event_scheduler = ON to my.cnf
Event runs as wrong userMissing privileges for the operationsCreate events as a user with sufficient privileges
No LIMIT on DELETE/UPDATEEvent locks the table for long periodsAlways use LIMIT in maintenance events
No logging or monitoringCan't tell if events are runningInsert into a log table inside the event body
Event and cron doing the same thingDouble-execution, wasted resourcesChoose one mechanism per task

Best Practices

  • Always add to my.cnfevent_scheduler = ON must survive restarts
  • Use LIMIT — batch operations in events to avoid long locks
  • Log execution — insert into a log table so you can verify events ran
  • Name with evt_ prefix — distinguish events from procedures and triggers
  • Add COMMENT — describe what the event does for future reference
  • Use ON COMPLETION PRESERVE for one-time events — so you can verify they executed
  • Monitor the schedulerSHOW PROCESSLIST shows the event scheduler thread

Hands-On Practice

Exercise 1: Create a One-Time Event (Easy)

Create an event that runs 5 minutes from now and inserts a row into a test_log table with the current timestamp. Verify it ran.

Exercise 2: Hourly Cleanup (Medium)

Create an event evt_purge_temp_files that:

  1. Runs every hour
  2. Deletes rows from temp_uploads where created_at < NOW() - INTERVAL 24 HOUR
  3. Limits to 5000 rows per run
  4. Logs the deletion count into maintenance_log

Exercise 3: Verify Event Execution (Advanced)

Create a monitoring query that shows:

  1. All events and their last execution time
  2. Which events are enabled vs disabled
  3. Any events that haven't run in the expected timeframe

Connection to Other Concepts

Related ConceptHow It Connects
Stored ProceduresEvents can CALL procedures for complex logic
TriggersTriggers are event-driven (data changes); events are time-driven
TransactionsEvent bodies can use transactions
Audit LoggingEvents can maintain retention on audit tables
Date ArithmeticNOW() - INTERVAL N DAY is the core of retention queries

What to Learn Next


Visual Learning Diagram

flowchart TD
A["MySQL Server starts"] --> B{"event_scheduler = ON?"}
B -->|No| C["❌ Events exist but never fire"]
B -->|Yes| D["Event Scheduler thread running"]
D --> E["Checks event schedules continuously"]
E --> F{"Event due?"}
F -->|Yes| G["Execute event body"]
G --> H["Log completion"]
H --> E
F -->|No| E

classDef warning fill:#ffc107,stroke:#333,color:#333
classDef success fill:#28a745,stroke:#fff,color:#fff
class C warning
class G,H success

Quick Reference

-- Enable scheduler
SET GLOBAL event_scheduler = ON;

-- Create recurring event
CREATE EVENT evt_name
ON SCHEDULE EVERY 1 HOUR
DO DELETE FROM temp WHERE created_at < NOW() - INTERVAL 1 DAY LIMIT 5000;

-- Create one-time event
CREATE EVENT evt_once
ON SCHEDULE AT NOW() + INTERVAL 1 HOUR
ON COMPLETION PRESERVE
DO INSERT INTO log (msg) VALUES ('Ran once');

-- Manage events
SHOW EVENTS;
ALTER EVENT evt_name DISABLE;
ALTER EVENT evt_name ENABLE;
DROP EVENT IF EXISTS evt_name;

What's Next