diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceType.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceType.java
index 294ccbff..c998f95a 100644
--- a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceType.java
+++ b/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceType.java
@@ -9,6 +9,8 @@ public enum LimboPersistenceType {
SINGLE_FILE(SingleFilePersistenceHandler.class),
+ SEGMENT_FILES(SegmentFilesPersistenceHolder.class),
+
DISABLED(NoOpPersistenceHandler.class);
private final Class extends LimboPersistenceHandler> implementationClass;
diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentConfiguration.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentConfiguration.java
new file mode 100644
index 00000000..d2f0d202
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentConfiguration.java
@@ -0,0 +1,94 @@
+package fr.xephi.authme.data.limbo.persistence;
+
+/**
+ * Configuration for the total number of segments to use.
+ *
+ * The {@link SegmentFilesPersistenceHolder} reduces the number of files by assigning each UUID
+ * to a segment. This enum allows to define how many segments the UUIDs should be distributed in.
+ *
+ * Segments are defined by a distribution and a length. The distribution defines
+ * to how many outputs a single hexadecimal characters should be mapped. So e.g. a distribution
+ * of 3 means that all hexadecimal characters 0-f should be distributed over three different
+ * outputs evenly. The {@link SegmentNameBuilder} simply uses hexadecimal characters as outputs,
+ * so e.g. with a distribution of 3 all hex characters 0-f are mapped to 0, 1, or 2.
+ *
+ * To ensure an even distribution the segments must be powers of 2. Trivially, to implement a
+ * distribution of 16, the same character may be returned as was input (since 0-f make up 16
+ * characters). A distribution of 1, on the other hand, means that the same output is returned
+ * regardless of the input character.
+ *
+ * The length parameter defines how many characters of a player's UUID should be used to
+ * create the segment ID. In other words, with a distribution of 2 and a length of 3, the first
+ * three characters of the UUID are taken into consideration, each mapped to one of two possible
+ * characters. For instance, a UUID starting with "0f5c9321" may yield the segment ID "010."
+ * Such a segment ID defines in which file the given UUID can be found and stored.
+ *
+ * The number of segments such a configuration yields is computed as {@code distribution ^ length},
+ * since distribution defines how many outputs there are per digit, and length defines the number
+ * of digits. For instance, a distribution of 2 and a length of 3 will yield segment IDs 000, 001,
+ * 010, 011, 100, 101, 110 and 111 (i.e. all binary numbers from 0 to 7).
+ *
+ * There are multiple possibilities to achieve certain segment totals, e.g. 8 different segments
+ * may be created by setting distribution to 8 and length to 1, or distr. to 2 and length to 3.
+ * Where possible, prefer a length of 1 (no string concatenation required) or a distribution of
+ * 16 (no remapping of the characters required).
+ */
+public enum SegmentConfiguration {
+
+ /** 1. */
+ ONE(1, 1),
+
+ /** 2. */
+ TWO(2, 1),
+
+ /** 4. */
+ FOUR(4, 1),
+
+ /** 8. */
+ EIGHT(8, 1),
+
+ /** 16. */
+ SIXTEEN(16, 1),
+
+ /** 32. */
+ THIRTY_TWO(2, 5),
+
+ /** 64. */
+ SIXTY_FOUR(4, 3),
+
+ /** 128. */
+ ONE_TWENTY(2, 7),
+
+ /** 256. */
+ TWO_FIFTY(16, 2);
+
+ private final int distribution;
+ private final int length;
+
+ SegmentConfiguration(int distribution, int length) {
+ this.distribution = distribution;
+ this.length = length;
+ }
+
+ /**
+ * @return the distribution size per character, i.e. how many possible outputs there are
+ * for any hexadecimal character
+ */
+ public int getDistribution() {
+ return distribution;
+ }
+
+ /**
+ * @return number of characters from a UUID that should be used to create a segment ID
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * @return number of segments to which this configuration will distribute UUIDs
+ */
+ public int getTotalSegments() {
+ return (int) Math.pow(distribution, length);
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentFilesPersistenceHolder.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentFilesPersistenceHolder.java
new file mode 100644
index 00000000..24751fe0
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/data/limbo/persistence/SegmentFilesPersistenceHolder.java
@@ -0,0 +1,132 @@
+package fr.xephi.authme.data.limbo.persistence;
+
+import com.google.common.io.Files;
+import com.google.common.reflect.TypeToken;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.data.limbo.LimboPlayer;
+import fr.xephi.authme.initialization.DataFolder;
+import fr.xephi.authme.service.BukkitService;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.LimboSettings;
+import fr.xephi.authme.util.FileUtils;
+import fr.xephi.authme.util.PlayerUtils;
+import org.bukkit.entity.Player;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Persistence handler for LimboPlayer objects by distributing the objects to store
+ * in various segments (buckets) based on the start of the player's UUID.
+ */
+class SegmentFilesPersistenceHolder implements LimboPersistenceHandler {
+
+ private static final Type LIMBO_MAP_TYPE = new TypeToken