Linux Software RAID with mdadm
mdadm (Multiple Devices Admin) manages Linux software RAID through the kernel's MD driver. It combines two or more physical disks or partitions into virtual block devices (/dev/md0, /dev/md1, …), supporting RAID 0, 1, 5, 6, and 10 for redundancy and performance without dedicated hardware.
RAID improves availability but is not a substitute for backups. See the backup and disaster recovery guide for proper backup strategy.
RAID levels
| Level | Min disks | Fault tolerance | Capacity | Read | Write | Best for |
|---|---|---|---|---|---|---|
| RAID 0 | 2 | None | N × disk | Excellent | Excellent | Scratch, cache, temp data |
| RAID 1 | 2 | 1 disk (N−1) | 1 × disk | Good | Moderate | Boot/OS volumes |
| RAID 5 | 3 | 1 disk | (N−1) × disk | Good | Moderate | Read-heavy general storage |
| RAID 6 | 4 | 2 disks | (N−2) × disk | Good | Moderate-slow | Large arrays, >4 TB disks |
| RAID 10 | 4 | 1 per mirror pair | N/2 × disk | Excellent | Excellent | Databases, high-IOPS |
RAID 10 layouts
The --layout option controls how mirror copies are distributed:
- near (default): copies placed consecutively, classic RAID 1+0
- far: copies placed far apart, improved sequential read performance, slight write penalty
- offset: copies striped consecutively, similar read characteristics to far without as much seeking
Creating arrays
# RAID 0
mdadm --create /dev/md0 --level=0 --raid-devices=2 /dev/sdb1 /dev/sdc1
# RAID 1
mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdb1 /dev/sdc1
# RAID 5
mdadm --create /dev/md0 --level=5 --raid-devices=3 /dev/sdb1 /dev/sdc1 /dev/sdd1
# RAID 6
mdadm --create /dev/md0 --level=6 --raid-devices=4 /dev/sd[bcde]1
# RAID 10 with far layout
mdadm --create /dev/md0 --level=10 --layout=f2 --raid-devices=4 /dev/sd[bcde]1
# With hot spare
mdadm --create /dev/md0 --level=5 --raid-devices=3 --spare-devices=1 /dev/sd[bcde]1
# With custom chunk size (default 512 KiB)
mdadm --create /dev/md0 --level=5 --raid-devices=3 --chunk=64 /dev/sd[bcd]1
# With write-intent bitmap
mdadm --create /dev/md0 --level=5 --raid-devices=3 --bitmap=internal /dev/sd[bcd]1Examining arrays
# Detailed view of an active array
mdadm --detail /dev/md0
# Brief view (suitable for mdadm.conf)
mdadm --detail --brief /dev/md0
# Scan all arrays and output ARRAY lines
mdadm --detail --scan
# Examine a component device's superblock
mdadm --examine /dev/sdb1
# Kernel view of active arrays
cat /proc/mdstatExample /proc/mdstat output:
Personalities : [raid1] [raid5] [raid6] [raid10]
md0 : active raid5 sda1[0] sdb1[1] sdc1[2]
209584128 blocks super 1.2 level 5, 512k chunk, algorithm 2 [3/3] [UUU]
bitmap: 0/1 pages [0KB], 65536KB chunk
unused devices: <none>The [UUU] field shows device health: U = up, _ = down/failed.
Monitoring
# Start monitor daemon (scans mdadm.conf)
mdadm --monitor --scan --daemonize
# With email alerts
mdadm --monitor --scan --mail=admin@example.com --daemonize
# Send a test alert
mdadm --monitor --scan --test
# Via systemd
systemctl enable --now mdmonitor.serviceFor proactive disk health monitoring beyond mdadm's event alerts, see the SMART monitoring guide.
mdadm.conf
The configuration file (/etc/mdadm.conf or /etc/mdadm/mdadm.conf on Debian) tells the initramfs which arrays to assemble at boot. Generate it after every array change:
# Generate ARRAY lines from active arrays
mdadm --detail --scan >> /etc/mdadm.conf
# Update initramfs so boot can find the array
update-initramfs -u # Debian/Ubuntu
dracut -f # RHEL/FedoraA typical file:
MAILADDR root
ARRAY /dev/md0 metadata=1.2 UUID=12345678:12345678:12345678:12345678 name=host:0Adding, removing, and replacing disks
# Mark a disk as failed
mdadm /dev/md0 --fail /dev/sdb1
# Remove the failed disk
mdadm /dev/md0 --remove /dev/sdb1
# Add a new (or replacement) disk
mdadm /dev/md0 --add /dev/sdb1
# Re-add a previously removed disk
mdadm /dev/md0 --re-add /dev/sdb1Complete disk replacement procedure
# 1. Identify the failed disk
mdadm --detail /dev/md0
cat /proc/mdstat
smartctl -a /dev/sdb | grep -i serial
# 2. Fail and remove
mdadm /dev/md0 --fail /dev/sdb1
mdadm /dev/md0 --remove /dev/sdb1
# 3. Physically replace the disk
# 4. Copy partition table from a healthy disk
sfdisk -d /dev/sdc | sfdisk /dev/sdb
# For GPT:
sgdisk -R /dev/sdb /dev/sdc
sgdisk -G /dev/sdb # randomize the disk GUID
# 5. Add the new partition to the array
mdadm /dev/md0 --add /dev/sdb1
# 6. Watch the rebuild
watch cat /proc/mdstatGrowing arrays
# Add a disk, then grow to include it (RAID 5: 3 → 4 disks)
mdadm /dev/md0 --add /dev/sdd1
mdadm --grow /dev/md0 --raid-devices=4 --backup-file=/tmp/grow_backup
# RAID level migration (0 → 5)
mdadm --grow /dev/md0 --level=5 --raid-devices=3
# Change chunk size
mdadm --grow /dev/md0 --chunk=128Reshaping (adding disks, changing level, changing chunk) is a long operation that rewrites the entire array. The --backup-file is required when growing without spare devices, shrinking, or changing RAID level/layout. It provides a safety net for critical metadata during reshape. The array remains usable during reshape but with a performance penalty.
Stopping and assembling
# Stop an array
mdadm --stop /dev/md0
# Assemble from explicit devices
mdadm --assemble /dev/md0 /dev/sdb1 /dev/sdc1 /dev/sdd1
# Assemble all arrays from mdadm.conf
mdadm --assemble --scan
# Force assembly of a dirty/degraded array
mdadm --assemble --scan --forceSuperblock versions
| Version | Metadata location | Notes |
|---|---|---|
| 0.90 | 64K-128K from end of device | Legacy. Max 28 devices, 2 TB per device (kernel < 3.1) / 4 TB (kernel >= 3.1). Required by GRUB Legacy / LILO. |
| 1.0 | 8K-12K from end of device | Required by Syslinux. Data starts at offset 0. |
| 1.1 | At byte 0 (start of device) | Rarely used in production. |
| 1.2 (default) | 4K from start, data at ~1 MiB | Default for all modern systems. 1 MiB alignment optimal for 4Kn drives. |
# Specify at creation time
mdadm --create /dev/md0 --level=1 --raid-devices=2 --metadata=1.0 /dev/sd[bc]1
# Zero out a superblock before reusing a disk
mdadm --zero-superblock /dev/sdb1RAID 5/6 write hole
The write hole is a fundamental timing problem in parity RAID: updating a stripe requires writing both data and parity blocks, and these are separate writes. If power is lost between them, data and parity become inconsistent. On a degraded array, inconsistent parity cannot be recalculated, leading to silent data corruption during rebuild.
Mitigations
# Write-intent bitmap (tracks dirty chunks for fast recovery)
mdadm --grow /dev/md0 --bitmap=internal
# Write journal (dedicated journal device, RAID 4/5/6)
mdadm --create /dev/md0 --level=5 --raid-devices=3 \
--write-journal=/dev/sdj1 /dev/sd[abc]1
# Consistency scrub
echo check > /sys/block/md0/md/sync_action
cat /sys/block/md0/md/mismatch_cnt
echo repair > /sys/block/md0/md/sync_actionWrite-intent bitmaps
| Bitmap type | Performance impact | Recovery speed |
|---|---|---|
internal | Significant random-write penalty (bitmap updated on every write) | Fast, only dirty chunks rebuilt |
external (on SSD) | Minimal if on fast device | Fast |
none | Best write performance | Full rebuild |
# Add internal bitmap
mdadm --grow /dev/md0 --bitmap=internal
# Add external bitmap on a separate file
mdadm --grow /dev/md0 --bitmap=/raidbitmap.bin
# Remove bitmap
mdadm --grow /dev/md0 --bitmap=nonePartitions vs whole disks
| Approach | Pros | Cons |
|---|---|---|
| Partitions | Tolerates size variation between replacement disks; allows multiple arrays per disk | Slightly more setup |
| Whole disks | Simpler; no partition table overhead | Replacement disk must be at least as large; no partition table warnings |
Recommendation: use partitions slightly smaller than full disk capacity (e.g., leave a 100 MB margin) to accommodate size variations between nominally identical disks from different manufacturers.
Many setups layer LVM on top of mdadm arrays for flexible volume management and snapshots. For TRIM support on RAID arrays, see the TRIM and discard guide.
Degraded boot
If the root filesystem is on RAID and a disk is missing at boot, the initramfs may refuse to start a dirty degraded array. Force it from the emergency shell:
# In initramfs emergency shell
mdadm --assemble --scan --force
mdadm --run /dev/md0Kernel parameter to allow dirty degraded starts:
md-mod.start_dirty_degraded=1Command quick reference
| Operation | Command |
|---|---|
| Create array | mdadm --create /dev/md0 --level=5 --raid-devices=3 /dev/sd[bcd]1 |
| Detail | mdadm --detail /dev/md0 |
| Status | cat /proc/mdstat |
| Fail disk | mdadm /dev/md0 --fail /dev/sdb1 |
| Remove disk | mdadm /dev/md0 --remove /dev/sdb1 |
| Add disk | mdadm /dev/md0 --add /dev/sdb1 |
| Grow array | mdadm --grow /dev/md0 --raid-devices=4 --backup-file=/tmp/bak |
| Stop | mdadm --stop /dev/md0 |
| Assemble | mdadm --assemble --scan |
| Scrub | echo check > /sys/block/md0/md/sync_action |
| Zero superblock | mdadm --zero-superblock /dev/sdb1 |
| Generate config | mdadm --detail --scan >> /etc/mdadm.conf |
Sources & references
- mdadm(8) — Linux manual page — primary man page for mdadm, documents all modes (create, assemble, grow, monitor) and RAID level specifications
- RAID arrays — Linux Kernel documentation — official kernel admin guide for MD RAID, covers boot-time assembly, superblock formats, and degraded boot
- RAID driver API — Linux Kernel documentation — kernel driver documentation for MD RAID, including RAID 4/5/6 cache and Partial Parity Log features
- dm-raid — Linux Kernel documentation — documents the device-mapper RAID target that bridges DM to MD, supporting LVM RAID
- RAID 4/5/6 cache (write hole mitigation) — official kernel documentation explaining the write hole problem and how write-through/write-back cache mitigates it
Frequently asked questions
How do you replace a failed disk in an mdadm RAID array?
Fail the disk with `mdadm /dev/md0 --fail`, remove it with `--remove`, copy the partition table from a healthy disk, then add the replacement with `--add`. The array rebuilds automatically; monitor with `watch cat /proc/mdstat`.
What is the RAID 5/6 write hole?
Updating a stripe requires separate writes for data and parity. If power is lost between them, data and parity become inconsistent. On a degraded array this causes silent corruption during rebuild. Write-intent bitmaps and a write journal mitigate it.
What does [UUU] mean in /proc/mdstat?
The bracket field shows per-device health. `U` means the device is up and `_` means it is down or failed. `[UUU]` indicates all three devices in a three-disk array are healthy.
How do you grow an mdadm array?
Add a disk with `mdadm --add`, then run `mdadm --grow` with the new `--raid-devices` count. Use `--backup-file` when reshaping without spares, shrinking, or changing RAID level. The array stays usable during reshape but with a performance penalty.
What is a write-intent bitmap in mdadm?
It tracks dirty chunks so only changed regions rebuild after a crash. Internal bitmaps have a random-write penalty; external bitmaps on SSD have minimal impact; no bitmap gives best write performance but requires a full rebuild.
Which mdadm superblock version should I use?
Version 1.2 is the default for modern systems, with 1 MiB alignment optimal for 4Kn drives. Use 0.90 only for GRUB Legacy or LILO, and 1.0 if Syslinux is required.
How do you boot from a degraded RAID array?
In the initramfs emergency shell run `mdadm --assemble --scan --force` and `mdadm --run /dev/md0`. To allow dirty degraded starts automatically, add the kernel parameter `md-mod.start_dirty_degraded=1`.