diff --git app/controllers/issues_controller.rb app/controllers/issues_controller.rb
index 8a8162b..bd648d1 100644
--- app/controllers/issues_controller.rb
+++ app/controllers/issues_controller.rb
@@ -118,6 +118,7 @@ class IssuesController < ApplicationController
     @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
     @priorities = IssuePriority.all
     @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
+    @custom_values = @issue.custom_field_values
     respond_to do |format|
       format.html { render :template => 'issues/show.rhtml' }
       format.api
@@ -285,6 +286,7 @@ private
     @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
     @time_entry.attributes = params[:time_entry]
 
+    @custom_values = @issue.custom_field_values
     @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
     @issue.init_journal(User.current, @notes)
     @issue.safe_attributes = params[:issue]
diff --git app/helpers/custom_fields_helper.rb app/helpers/custom_fields_helper.rb
index 3028cd4..fdccf06 100644
--- app/helpers/custom_fields_helper.rb
+++ app/helpers/custom_fields_helper.rb
@@ -49,7 +49,12 @@ module CustomFieldsHelper
       blank_option = custom_field.is_required? ?
                        (custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') : 
                        '<option></option>'
-      select_tag(field_name, blank_option + options_for_select(custom_field.possible_values_options(custom_value.customized), custom_value.value), :id => field_id)
+      multi_image = custom_field.allow_multi ?
+                    link_to_function(image_tag('bullet_toggle_plus.png'), "toggle_multi_custom('#{custom_field.id}');", :style => "vertical-align: bottom;") :
+                    ''
+      multiple = custom_field.allow_multi && custom_value.value.is_a?(Array) && custom_value.value.length > 1
+      select_name = custom_field.allow_multi ? "#{name}[custom_multi_values][#{custom_field.id}][]" : field_name
+      select_tag(select_name, blank_option + options_for_select(custom_field.possible_values, custom_value.value), :id => field_id, :multiple => multiple) + multi_image
     else
       text_field_tag(field_name, custom_value.value, :id => field_id)
     end
@@ -92,7 +97,7 @@ module CustomFieldsHelper
   # Return a string used to display a custom value
   def show_value(custom_value)
     return "" unless custom_value
-    format_value(custom_value.value, custom_value.custom_field.field_format)
+    format_value((custom_value.value.is_a?(Array) ? custom_value.value.join("\n") : custom_value.value), custom_value.custom_field.field_format)
   end
   
   # Return a string used to display a custom value
diff --git app/models/custom_field.rb app/models/custom_field.rb
index 0e8151e..b13028b 100644
--- app/models/custom_field.rb
+++ app/models/custom_field.rb
@@ -33,6 +33,8 @@ class CustomField < ActiveRecord::Base
   def before_validation
     # make sure these fields are not searchable
     self.searchable = false if %w(int float date bool).include?(field_format)
+    # make sure only list field_format have allow_multi option
+    self.allow_multi = false unless field_format == 'list'
     true
   end
   
diff --git app/models/custom_value.rb app/models/custom_value.rb
index 97bd47f..e11a437 100644
--- app/models/custom_value.rb
+++ app/models/custom_value.rb
@@ -69,3 +69,48 @@ protected
     end
   end
 end
+
+class CustomValuesCollection < Array
+  attr_accessor :custom_field
+  
+  def initialize(custom_field, custom_values=[])
+    @custom_field = custom_field if custom_field.is_a?(CustomField)    
+    custom_values.map{ |x| self << x }
+    self
+  end
+
+  def value
+    self.uniq.map(&:value).delete_if {|x| x.blank?}
+  end
+
+  def value=(new_value)
+    self.delete_if{ |x| true }
+    new_value.map{ |x| self << x }
+  end
+  
+  def save
+    self.compact.each(&:save)
+  end
+
+  def valid?
+    self.inject(true){ |bool,v| bool && v.valid? }
+  end
+
+  def validate
+    self.uniq.map(&:validate)
+  end
+
+  def custom_field_id
+    @custom_field.id
+  end
+
+  def method_missing(symbol, *args)
+    if @custom_field.respond_to?(symbol)
+      @custom_field.send(symbol, *args)
+    elsif self.first && self.first.respond_to?(symbol)
+      self.first.send(symbol, *args)
+    else
+      super
+    end
+  end
+end
diff --git app/models/issue.rb app/models/issue.rb
index 79c4915..2ad0d86 100644
--- app/models/issue.rb
+++ app/models/issue.rb
@@ -264,6 +264,7 @@ class Issue < ActiveRecord::Base
     'due_date',
     'done_ratio',
     'estimated_hours',
+    'custom_multi_values',
     'custom_field_values',
     'custom_fields',
     'lock_version',
@@ -393,7 +394,7 @@ class Issue < ActiveRecord::Base
     @issue_before_change = self.clone
     @issue_before_change.status = self.status
     @custom_values_before_change = {}
-    self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
+    custom_field_values.each {|c| @custom_values_before_change.store c.custom_field.id, c.value }
     # Make sure updated_on is updated when adding a note.
     updated_on_will_change!
     @current_journal
@@ -886,7 +887,7 @@ class Issue < ActiveRecord::Base
                                                       :value => send(c))
       }
       # custom fields changes
-      custom_values.each {|c|
+      custom_field_values.each {|c|
         next if (@custom_values_before_change[c.custom_field_id]==c.value ||
                   (@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?))
         @current_journal.details << JournalDetail.new(:property => 'cf',
diff --git app/models/journal_detail.rb app/models/journal_detail.rb
index 886fe3e..aaa5dcb 100644
--- app/models/journal_detail.rb
+++ app/models/journal_detail.rb
@@ -22,6 +22,8 @@ class JournalDetail < ActiveRecord::Base
   private
   
   def normalize_values
+    self.value = value.join(", ") if value && value.is_a?(Array)
+    self.old_value = old_value.join(", ") if old_value && old_value.is_a?(Array)
     self.value = normalize(value)
     self.old_value = normalize(old_value)
   end
diff --git app/views/custom_fields/_form.rhtml app/views/custom_fields/_form.rhtml
index 2900af9..f05abf9 100644
--- app/views/custom_fields/_form.rhtml
+++ app/views/custom_fields/_form.rhtml
@@ -5,6 +5,7 @@
 function toggle_custom_field_format() {
   format = $("custom_field_field_format");
   p_length = $("custom_field_min_length");
+  p_multi = $("custom_field_allow_multi");
   p_regexp = $("custom_field_regexp");
   p_values = $("custom_field_possible_values");
   p_searchable = $("custom_field_searchable");
@@ -19,6 +20,7 @@ function toggle_custom_field_format() {
       Element.hide(p_regexp.parentNode);
       if (p_searchable) Element.show(p_searchable.parentNode);
       Element.show(p_values.parentNode);
+      Element.show(p_multi.parentNode);
       break;
     case "bool":
       p_default.setAttribute('type','checkbox');
@@ -26,12 +28,14 @@ function toggle_custom_field_format() {
       Element.hide(p_regexp.parentNode);
       if (p_searchable) Element.hide(p_searchable.parentNode);
       Element.hide(p_values.parentNode);
+      Element.hide(p_multi.parentNode);
       break;
     case "date":
       Element.hide(p_length.parentNode);
       Element.hide(p_regexp.parentNode);
       if (p_searchable) Element.hide(p_searchable.parentNode);
       Element.hide(p_values.parentNode);
+      Element.hide(p_multi.parentNode);
       break;
     case "float":
     case "int":
@@ -39,6 +43,7 @@ function toggle_custom_field_format() {
       Element.show(p_regexp.parentNode);
       if (p_searchable) Element.hide(p_searchable.parentNode);
       Element.hide(p_values.parentNode);
+      Element.hide(p_multi.parentNode);
       break;
 		case "user":
     case "version":
@@ -53,6 +58,7 @@ function toggle_custom_field_format() {
       Element.show(p_regexp.parentNode);
       if (p_searchable) Element.show(p_searchable.parentNode);
       Element.hide(p_values.parentNode);
+      Element.hide(p_multi.parentNode);
       break;
   }
 }
@@ -91,6 +97,7 @@ when "IssueCustomField" %>
     <p><%= f.check_box :is_for_all %></p>
     <p><%= f.check_box :is_filter %></p>
     <p><%= f.check_box :searchable %></p>
+    <p><%= f.check_box :allow_multi %></p>
     
 <% when "UserCustomField" %>
     <p><%= f.check_box :is_required %></p>
diff --git app/views/issues/_form_custom_fields.rhtml app/views/issues/_form_custom_fields.rhtml
index 7a66ed3..549a078 100644
--- app/views/issues/_form_custom_fields.rhtml
+++ app/views/issues/_form_custom_fields.rhtml
@@ -1,3 +1,15 @@
+<script type="text/javascript">
+//<![CDATA[
+function toggle_multi_custom(field) {
+  select = $('issue_custom_field_values_' + field);
+    if (select.multiple == true) {
+      select.multiple = false;
+    } else {
+      select.multiple = true;
+  }
+}
+//]]>
+</script>
 <div class="splitcontentleft">
 <% i = 0 %>
 <% split_on = (@issue.custom_field_values.size / 2.0).ceil - 1 %>
diff --git config/locales/en.yml config/locales/en.yml
index 401d608..a8bd050 100644
--- config/locales/en.yml
+++ config/locales/en.yml
@@ -292,6 +292,7 @@ en:
   field_time_entries: Log time
   field_time_zone: Time zone
   field_searchable: Searchable
+  field_allow_multi: Allow multiple choices
   field_default_value: Default value
   field_comments_sorting: Display comments
   field_parent_title: Parent page
diff --git db/migrate/20100512172200_add_custom_fields_multi.rb db/migrate/20100512172200_add_custom_fields_multi.rb
new file mode 100644
index 0000000..e73e3c7
--- /dev/null
+++ db/migrate/20100512172200_add_custom_fields_multi.rb
@@ -0,0 +1,9 @@
+class AddCustomFieldsMulti < ActiveRecord::Migration
+  def self.up
+    add_column :custom_fields, :allow_multi, :boolean, :default => false
+  end
+
+  def self.down
+    remove_column :custom_fields, :allow_multi
+  end
+end
\ No newline at end of file
diff --git test/unit/custom_value_test.rb test/unit/custom_value_test.rb
index 49ae28c..1c9b435 100644
--- test/unit/custom_value_test.rb
+++ test/unit/custom_value_test.rb
@@ -78,6 +78,29 @@ class CustomValueTest < ActiveSupport::TestCase
     assert v.valid?
   end
 
+  def test_multi_list_field_validation
+    f = CustomField.new(:field_format => 'list', :allow_multi => true, :possible_values => ['value1', 'value2'])
+    v = CustomValuesCollection.new(:custom_field => f, :value => [])
+    assert v.valid?
+    v << CustomValue.new(:custom_field => f, :value => 'value1')
+    assert v.valid?
+    v << CustomValue.new(:custom_field => f, :value => 'value2')
+    assert v.valid?
+    v << CustomValue.new(:custom_field => f, :value => 'abc')
+    assert !v.valid?
+  end
+
+  def test_multi_list_field_value
+    f = CustomField.new(:field_format => 'list', :allow_multi => true, :possible_values => ['value1', 'value2'])
+    v = CustomValuesCollection.new(:custom_field => f, :value => [])
+    v << CustomValue.new(:custom_field => f, :value => 'value1')
+    c = CustomValue.new(:custom_field => f, :value => 'value2')
+    v << c
+    assert_equal ['value1', 'value2'], v.value
+    v << c
+    assert ['value1', 'value2'], v.value
+  end
+
   def test_int_field_validation
     f = CustomField.new(:field_format => 'int')
     v = CustomValue.new(:custom_field => f, :value => '')
diff --git vendor/plugins/acts_as_customizable/lib/acts_as_customizable.rb vendor/plugins/acts_as_customizable/lib/acts_as_customizable.rb
index 10ba123..d41ee79 100644
--- vendor/plugins/acts_as_customizable/lib/acts_as_customizable.rb
+++ vendor/plugins/acts_as_customizable/lib/acts_as_customizable.rb
@@ -69,17 +69,64 @@ module Redmine
           @custom_field_values_changed = true
           values = values.stringify_keys
           custom_field_values.each do |custom_value|
-            custom_value.value = values[custom_value.custom_field_id.to_s] if values.has_key?(custom_value.custom_field_id.to_s)
+            if custom_value.is_a? CustomValuesCollection
+              if custom_value.empty?
+                values.each do |key, value|
+                  if (custom_value.custom_field_id == key.to_i && value.is_a?(Array))
+                    if value.empty?
+                      custom_value << custom_values.build(:custom_field => custom_value.custom_field, :value => nil)
+                    else
+                      value.each do |v|
+                        custom_value << custom_values.build(:custom_field => custom_value.custom_field, :value => v)
+                      end
+                    end
+                  end
+                end
+              end
+              CustomValue # otherwise Rails doesn't know the CustomValuesCollection class
+              custom_value = CustomValuesCollection.new custom_value.custom_field, custom_value
+              #end
+            else
+              custom_value.value = values[custom_value.custom_field_id.to_s] if values.has_key?(custom_value.custom_field_id.to_s)
+            end
           end if values.is_a?(Hash)
           self.custom_values = custom_field_values
         end
         
         def custom_field_values
-          @custom_field_values ||= available_custom_fields.collect { |x| custom_values.detect { |v| v.custom_field == x } || custom_values.build(:customized => self, :custom_field => x, :value => nil) }
+          @custom_field_values ||= available_custom_fields.collect do |x|
+            if x.allow_multi
+              CustomValue # otherwise Rails doesn't know the CustomValuesCollection class
+              CustomValuesCollection.new x, custom_values.select{ |v| v.custom_field == x }
+            else
+              custom_values.detect { |v| v.custom_field == x } || custom_values.build(:custom_field => x, :value => nil)
+            end
+          end
         end
         
-        def visible_custom_field_values
-          custom_field_values.select(&:visible?)
+        def custom_multi_values=(values)
+          values.each do |key, value|
+            value.delete_if {|v| v.to_s == ""} if value.length > 1
+          end
+          
+          @old_custom_values ||= custom_values.select{ |x| x.custom_field.allow_multi }
+          @custom_field_values_changed = true
+          values = values.stringify_keys
+          values.each do |key, value|
+            custom_value = custom_field_values.detect{ |c| c.custom_field.id == key.to_i && c.allow_multi }
+            value.each do |v|
+              old = @old_custom_values.detect{ |u| u.custom_field == custom_value.custom_field && u.value == v }
+              if old.blank?
+                custom_value << custom_values.build(:custom_field => custom_value.custom_field, :value => v)
+              else
+                custom_value << old unless custom_value.include?(old)
+                @old_custom_values.delete old
+              end
+            end if values.is_a?(Hash) && custom_value != nil && values.has_key?(custom_value.custom_field.id.to_s)
+          end
+          #delete old normal values
+          @custom_field_values.each { |c| c.delete_if{ |x| @old_custom_values.include?(x) } if c.is_a?(CustomValuesCollection) }
+          @custom_values.delete_if { |c| @old_custom_values.include?(c) }
         end
         
         def custom_field_values_changed?
@@ -93,6 +140,7 @@ module Redmine
         
         def save_custom_field_values
           custom_field_values.each(&:save)
+          @old_custom_values.each(&:destroy) unless @old_custom_values.blank?
           @custom_field_values_changed = false
           @custom_field_values = nil
         end
